From 0dcfac8f15c4541c571e7558d7d9c317844e4d91 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 18 Aug 2022 19:06:54 +0200 Subject: [PATCH 1/7] Update SOGo to 5.7.1 --- data/Dockerfiles/sogo/Dockerfile | 6 +++--- docker-compose.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index 72f7d816..f08600ac 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -2,7 +2,7 @@ FROM debian:bullseye-slim LABEL maintainer "Andre Peters " ARG DEBIAN_FRONTEND=noninteractive -ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/ +ARG SOGO_DEBIAN_REPOSITORY=http://packages.sogo.nu/nightly/5/debian/ ENV LC_ALL C ENV GOSU_VERSION 1.14 @@ -30,7 +30,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \ && gosu nobody true \ && mkdir /usr/share/doc/sogo \ && touch /usr/share/doc/sogo/empty.sh \ - && apt-key adv --keyserver keyserver.ubuntu.com --recv-key 0x810273C4 \ + && apt-key adv --keyserver keys.openpgp.org --recv-key 74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 \ && echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \ && apt-get update && apt-get install -y --no-install-recommends \ sogo \ @@ -52,4 +52,4 @@ RUN chmod +x /bootstrap-sogo.sh \ ENTRYPOINT ["/docker-entrypoint.sh"] -CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9d5f9473..9fbfef59 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -168,7 +168,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.109 + image: mailcow/sogo:1.110 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER} From 7a23e4fd4e02df90dd8ac0fe7968f47fda6839cf Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Wed, 24 Aug 2022 12:12:41 +0200 Subject: [PATCH 2/7] Fix for Sieve error (due to IPv6 Comp from SOGo) --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index ac7aeb1d..801d422a 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -307,11 +307,18 @@ namespace { } EOF +# Get SOGo IPv6 from Dig +SOGO_V6=$(dig +answer sogo AAAA +short) + cat < /etc/dovecot/sogo_trusted_ip.conf # Autogenerated by mailcow remote ${IPV4_NETWORK}.248 { disable_plaintext_auth = no } + +remote ${SOGO_V6} { + disable_plaintext_auth = no +} EOF # Create random master Password for SOGo SSO From 575eab1cf02d5ef75a86df4fd400d595dd14c113 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Wed, 24 Aug 2022 12:26:14 +0200 Subject: [PATCH 3/7] Implemented Check if IPv6 is disabled --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 801d422a..aa1aa0ae 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -310,6 +310,7 @@ EOF # Get SOGo IPv6 from Dig SOGO_V6=$(dig +answer sogo AAAA +short) +if [ $SOGO_V6 ]; then cat < /etc/dovecot/sogo_trusted_ip.conf # Autogenerated by mailcow remote ${IPV4_NETWORK}.248 { @@ -321,6 +322,15 @@ remote ${SOGO_V6} { } EOF +else +cat < /etc/dovecot/sogo_trusted_ip.conf +# Autogenerated by mailcow +remote ${IPV4_NETWORK}.248 { + disable_plaintext_auth = no +} +EOF +fi + # Create random master Password for SOGo SSO RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1) echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass From 0c11cf747a1eb353aaddeeb8d2d6578dfd88df2c Mon Sep 17 00:00:00 2001 From: milkmaker Date: Thu, 25 Aug 2022 18:15:27 +0200 Subject: [PATCH 4/7] Translations update from Weblate (#4722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Web] Updated lang.cs.json [CI SKIP] Co-authored-by: Vojtěch Kaizr Co-authored-by: milkmaker * [Web] Updated lang.fr.json [CI SKIP] Co-authored-by: milkmaker Co-authored-by: ppelleti2 * [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Updated lang.tr.json [CI SKIP] [Web] Added lang.tr.json [CI SKIP] Co-authored-by: Peter Co-authored-by: milkmaker Co-authored-by: therudeboy * [Web] Updated lang.ro.json [CI SKIP] Co-authored-by: Vlad M Co-authored-by: milkmaker * [Web] Updated lang.it.json [CI SKIP] Co-authored-by: Peter * [Web] Turkish translation * [Web] Turkish translation Co-authored-by: Vojtěch Kaizr Co-authored-by: ppelleti2 Co-authored-by: Peter Co-authored-by: therudeboy Co-authored-by: Vlad M --- data/web/inc/vars.inc.php | 1 + data/web/lang/lang.cs.json | 2 +- data/web/lang/lang.fr.json | 7 +++- data/web/lang/lang.it.json | 3 +- data/web/lang/lang.ro.json | 5 ++- data/web/lang/lang.tr.json | 85 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 data/web/lang/lang.tr.json diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 02366c75..87684b7a 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -100,6 +100,7 @@ $AVAILABLE_LANGUAGES = array( 'ru' => 'Pусский (Russian)', 'sk' => 'Slovenčina (Slovak)', 'sv' => 'Svenska (Swedish)', + 'tr' => 'Türkçe (Turkish)', 'uk' => 'Українська (Ukrainian)', 'zh' => '中文 (Chinese)' ); diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json index 309331aa..e8b70b4a 100644 --- a/data/web/lang/lang.cs.json +++ b/data/web/lang/lang.cs.json @@ -839,7 +839,7 @@ "confirm_delete": "Potvrdit smazání prvku.", "danger": "Nebezpečí", "deliver_inbox": "Doručit do schránky", - "disabled_by_config": "Funkce karanténa je momentálně vypnuta v nastavení systému.", + "disabled_by_config": "Funkce karanténa je momentálně vypnuta v nastavení systému. Nastavte, prosím, prvkům karantény hodnoty \"počet zadržených zpráv\" a \"maximální velikost\".", "download_eml": "Stáhnout (.eml)", "empty": "Žádné výsledky", "high_danger": "Vysoké nebezpečí", diff --git a/data/web/lang/lang.fr.json b/data/web/lang/lang.fr.json index 02d35d35..f3ff355c 100644 --- a/data/web/lang/lang.fr.json +++ b/data/web/lang/lang.fr.json @@ -102,7 +102,8 @@ "timeout2": "Délai d'expiration pour la connexion à l'hôte local", "username": "Nom d'utilisateur", "validate": "Valider", - "validation_success": "Validation réussie" + "validation_success": "Validation réussie", + "bcc_dest_format": "La destination Cci doit être une seule adresse e-mail valide.
Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici." }, "admin": { "access": "Accès", @@ -322,7 +323,9 @@ "yes": "✓", "api_read_write": "Accès Lecture-Écriture", "oauth2_add_client": "Ajouter un client OAuth2", - "password_policy": "Politique de mots de passe" + "password_policy": "Politique de mots de passe", + "admins": "Administrateurs", + "api_read_only": "Accès lecture-seule" }, "danger": { "access_denied": "Accès refusé ou données de formulaire non valides", diff --git a/data/web/lang/lang.it.json b/data/web/lang/lang.it.json index 569951e0..a4a636a9 100644 --- a/data/web/lang/lang.it.json +++ b/data/web/lang/lang.it.json @@ -973,7 +973,8 @@ "verified_fido2_login": "Verified FIDO2 login", "verified_totp_login": "Verified TOTP login", "verified_webauthn_login": "Verified WebAuthn login", - "verified_yotp_login": "Verified Yubico OTP login" + "verified_yotp_login": "Verified Yubico OTP login", + "domain_add_dkim_available": "Esisteva già una chiave DKIM" }, "tfa": { "api_register": "%s usa le API Yubico Cloud. Richiedi una chiave API qui", diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json index e769e041..65030ea4 100644 --- a/data/web/lang/lang.ro.json +++ b/data/web/lang/lang.ro.json @@ -979,7 +979,8 @@ "verified_totp_login": "Autentificarea TOTP verificată", "verified_webauthn_login": "Autentificarea WebAuthn verificată", "verified_fido2_login": "Conectare FIDO2 verificată", - "verified_yotp_login": "Autentificarea Yubico OTP verificată" + "verified_yotp_login": "Autentificarea Yubico OTP verificată", + "domain_add_dkim_available": "O cheie DKIM deja a existat" }, "tfa": { "api_register": "%s utilizează API-ul Yubico Cloud. Obțineți o cheie API pentru cheia dvs. de aici", @@ -990,7 +991,7 @@ "enter_qr_code": "Codul tău TOTP dacă dispozitivul tău nu poate scana codurile QR", "error_code": "Cod de eroare", "init_webauthn": "Inițializare, vă rugăm așteptați...", - "key_id": "Un identificator pentru YubiKey", + "key_id": "Un identificator pentru dispozitiv", "key_id_totp": "Un identificator pentru cheia ta", "none": "Dezactivează", "reload_retry": "- (reîncărcați browserul dacă eroarea persistă)", diff --git a/data/web/lang/lang.tr.json b/data/web/lang/lang.tr.json new file mode 100644 index 00000000..697c7483 --- /dev/null +++ b/data/web/lang/lang.tr.json @@ -0,0 +1,85 @@ +{ + "acl": { + "alias_domains": "Takma alan adı ekle", + "app_passwds": "Uygulama şifrelerini yönet", + "delimiter_action": "Sınırlama işlemi", + "domain_relayhost": "Bir alan adı için relayhost sunucusunu değiştir", + "eas_reset": "EAS cihazlarını sıfırla", + "mailbox_relayhost": "Bir posta kutusunun relayhost sunucularını değiştir", + "pushover": "Bildirim", + "quarantine": "Karantina işlemleri", + "quarantine_attachments": "Ekleri karantinaya al", + "quarantine_notification": "Karantina bildirimlerini değiştir", + "smtp_ip_access": "SMTP sunucularının değiştirilmesine izin ver", + "sogo_access": "SOGo erişiminin yönetilmesine izin ver", + "domain_desc": "Alan adı açıklamasını değiştir", + "extend_sender_acl": "Gönderenin acl'sini harici adreslere göre genişletmeye izin ver", + "spam_policy": "Engellenenler / İzin verilenler" + }, + "add": { + "activate_filter_warn": "Aktif edilirse diğer tüm filtreler devre dışı bırakılacak.", + "add_domain_only": "Sadece alan adı ekle", + "alias_address": "Takma ad adres(leri)", + "alias_domain": "Takma alan adı", + "alias_domain_info": "Sadece geçerli alan adları (virgülle ayırın).", + "backup_mx_options": "İletme ayarları", + "delete2": "Kaynakta olmayan hedefteki mesajları sil", + "delete2duplicates": "Hedefteki kopyaları sil", + "disable_login": "Giriş yapmaya izin verme ( Gelen mailler yine de kabul edilir)", + "domain": "Alan adı", + "domain_matches_hostname": "Alan adı %s ana bilgisayar adıyla eşleşiyor", + "add_domain_restart": "Alan adı ekleyin ve SOGo'yu yeniden başlatın", + "alias_address_info": "Bir alan adına ilişkin tüm iletileri yakalamak için tam e-posta adresi veya @example.com olacak şeklinde girin (virgülle ayırın).sadece mailcow alan adları.", + "domain_quota_m": "Toplam alan adı kotası (MiB)", + "generate": "oluştur", + "goto_ham": "Ham olarakişaretle", + "goto_null": "Postaları sessizce çöpe at", + "goto_spam": "Spam olarakişaretle", + "hostname": "Ana sunucu", + "kind": "Tür", + "mailbox_quota_m": "Posta kutusu başına maksimum kota (MiB)", + "max_aliases": "Maksimum olası takma adı", + "max_mailboxes": "Maksimum olası posta kutusu", + "nexthop": "Sonraki atlama", + "port": "Port", + "public_comment": "Genel yorum", + "relay_all": "Tüm alıcılara ilet", + "relay_all_info": "Eğer hiçbir alıcıya iletilmemesini seçerseniz, aktarılması gereken her alıcı için bir (\"kör\") posta kutusu eklemeniz gerekecektir.", + "relay_domain": "Bu alan adını ilet", + "relay_transport_info": "
Bilgi
Bu etki alanı için özel bir hedef için aktarım eşlemeleri tanımlayabilirsiniz. Ayarlanmazsa, bir MX araması yapılacaktır.", + "relay_unknown_only": "Yalnızca mevcut olmayan posta kutularını ilet. Mevcut posta kutuları yerel olarak teslim edilecektir.", + "relayhost_wrapped_tls_info": "Lütfen TLS ile örtülmüş portları kullanmayın (çoğu 465 portunda çalışır).
\nÖrtülmemiş port kullan ve STARTTLS üzerinden yayınla. TLS'yi zorlamak için bir TLS ilkesi \"TLS ilke eşlemeleri\" sayfası içinde oluşturulabilir.", + "skipcrossduplicates": "Klasörler arasında yinelenen mesajları atlayın (ilk mesaj seçilir)", + "target_address": "Adreslere git", + "target_address_info": "Tam e-posta adres(leri) girin ( virgülle ayırın).", + "target_domain": "Hedef alan adı", + "timeout1": "Uzak ana bilgisayara bağlantısı zaman aşımına uğradı", + "timeout2": "Yerel ana bilgisayara bağlantı zaman aşımına uğradı" + }, + "admin": { + "action": "İşlem", + "add_forwarding_host": "Yönlendirme sunucusu ekle", + "add_transport": "İletim ekle", + "admin_details": "Yönetici detaylarını düzenle", + "admin_domains": "Alan adı atamaları", + "add_domain_admin": "Alan adı yöneticisi ekle", + "api_info": "API üzerinde çalışmalar devam etmektedir. Belgeler /apiadresinde bulunabilir", + "apps_name": "\"mailcow Uygulamaları\" adı", + "authed_user": "Yetkili kullanıcı", + "ban_list_info": "Aşağıdaki yasaklı IP'lerin listesine bakın: ağ (kalan yasak süresi) - [işlemler].
Yasağı kaldırılmak üzere sıraya alınan IP'ler birkaç saniye içinde aktif yasak listesinden kaldırılacaktır.
Kırmızı etiketler, kara listeye alınarak aktif kalıcı yasakları gösterir.", + "configuration": "Yapılandırma", + "dkim_from_title": "Verilerin kopyalanacağı kaynak alan adı", + "dkim_to": "Kime", + "dkim_to_title": "Hedef alan ad(ları) üzerinde yazılacak", + "dkim_domains_wo_keys": "Eksik anahtarları olan alan adlarını seçin", + "domain": "Alan adı", + "domain_admin": "Alan adı yöneticisi", + "domain_admins": "Alan adı yöneticileri", + "domain_s": "Alan ad(ları)", + "duplicate": "Çift", + "duplicate_dkim": "Çift DKIM kayıtları", + "f2b_ban_time": "Yasaklama süresi (saniye)", + "f2b_max_attempts": "Maksimum giriş denemesi", + "f2b_retry_window": "Maksimum girişim için deneme pencere(leri)" + } +} From 2ed453a400d26d514715cc0dfdfb33f1fcfba793 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Wed, 31 Aug 2022 11:31:55 +0200 Subject: [PATCH 5/7] fix mailbox tfa --- data/web/inc/functions.inc.php | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 4f70b4c2..98f8075e 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -937,11 +937,13 @@ function check_login($user, $pass, $app_passwd_data = false) { } foreach ($rows as $row) { // verify password - if ($app_passwd_data['eas'] !== true && $app_passwd_data['dav'] !== true){ - if (verify_hash($row['password'], $pass) !== false) { + if (verify_hash($row['password'], $pass) !== false) { + if (!array_key_exists("app_passwd_id", $row)){ + // password is not a app password // check for tfa authenticators $authenticators = get_tfa($user); if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) { + // authenticators found, init TFA flow $_SESSION['pending_mailcow_cc_username'] = $user; $_SESSION['pending_mailcow_cc_role'] = "user"; $_SESSION['pending_tfa_methods'] = $authenticators['additional']; @@ -953,6 +955,7 @@ function check_login($user, $pass, $app_passwd_data = false) { ); return "pending"; } else { + // no authenticators found, login successfull // Reactivate TFA if it was set to "deactivate TFA for next login" $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user"); $stmt->execute(array(':user' => $user)); @@ -960,22 +963,19 @@ function check_login($user, $pass, $app_passwd_data = false) { unset($_SESSION['ldelay']); return "user"; } - } - } elseif ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) { - if (array_key_exists("app_passwd_id", $row)){ - if (verify_hash($row['password'], $pass) !== false) { - $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV'; - $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); - $stmt->execute(array( - ':service' => $service, - ':app_id' => $row['app_passwd_id'], - ':username' => $user, - ':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']) - )); + } elseif ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) { + // password is a app password + $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV'; + $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); + $stmt->execute(array( + ':service' => $service, + ':app_id' => $row['app_passwd_id'], + ':username' => $user, + ':remote_addr' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']) + )); - unset($_SESSION['ldelay']); - return "user"; - } + unset($_SESSION['ldelay']); + return "user"; } } } @@ -994,7 +994,7 @@ function check_login($user, $pass, $app_passwd_data = false) { $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $user, '*'), - 'msg' => 'login_failed' + 'msg' => array('login_failed', $pass, $rows, $app_passwd_data, array_key_exists("app_passwd_id", $row)) ); sleep($_SESSION['ldelay']); From a161aa2c925008de927a7a62fad1576be2e69b3b Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Wed, 31 Aug 2022 11:37:45 +0200 Subject: [PATCH 6/7] remove testing debug log --- data/web/inc/functions.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 98f8075e..9c7a7894 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -994,7 +994,7 @@ function check_login($user, $pass, $app_passwd_data = false) { $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $user, '*'), - 'msg' => array('login_failed', $pass, $rows, $app_passwd_data, array_key_exists("app_passwd_id", $row)) + 'msg' => 'login_failed' ); sleep($_SESSION['ldelay']); From a40df1ff87a5ff7bf263fa2dbfb0326007a739fc Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 1 Sep 2022 09:53:08 +0200 Subject: [PATCH 7/7] fix tfa modal trigger from dav/eas login --- data/web/inc/functions.inc.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 9c7a7894..c26682c6 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -935,14 +935,15 @@ function check_login($user, $pass, $app_passwd_data = false) { $stmt->execute(array(':user' => $user)); $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC)); } - foreach ($rows as $row) { + foreach ($rows as $row) { // verify password if (verify_hash($row['password'], $pass) !== false) { if (!array_key_exists("app_passwd_id", $row)){ // password is not a app password // check for tfa authenticators $authenticators = get_tfa($user); - if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) { + if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && + $app_passwd_data['eas'] !== true && $app_passwd_data['dav'] !== true) { // authenticators found, init TFA flow $_SESSION['pending_mailcow_cc_username'] = $user; $_SESSION['pending_mailcow_cc_role'] = "user"; @@ -954,7 +955,7 @@ function check_login($user, $pass, $app_passwd_data = false) { 'msg' => array('logged_in_as', $user) ); return "pending"; - } else { + } else if (!isset($authenticators['additional']) || !is_array($authenticators['additional']) || count($authenticators['additional']) == 0) { // no authenticators found, login successfull // Reactivate TFA if it was set to "deactivate TFA for next login" $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");