From b888e920f4f5a424806ced495f2e0e1f0180d466 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 21 Jul 2024 10:41:24 +0200 Subject: [PATCH] merge current enhancements from main branch to v2.2 (#1261) --- index.php | 62 ++++++++++++++++--- install/froxlor.sql.php | 15 ++++- install/updates/froxlor/update_2.2.inc.php | 23 +++++++ lib/Froxlor/Api/Commands/Emails.php | 54 ++++++++-------- lib/Froxlor/Api/Commands/SubDomains.php | 7 ++- lib/Froxlor/Cli/MasterCron.php | 3 +- lib/Froxlor/Dns/Dns.php | 2 +- lib/Froxlor/Froxlor.php | 4 +- lib/Froxlor/UI/Callbacks/Domain.php | 10 ++- lib/Froxlor/UI/Callbacks/Text.php | 8 +++ .../domains/formfield.domains_edit.php | 21 ++++--- .../admin/tablelisting.admins.php | 6 ++ .../admin/tablelisting.customers.php | 6 ++ lib/tables.inc.php | 1 + lng/de.lng.php | 3 + lng/en.lng.php | 3 + logfiles_viewer.php | 4 ++ ssl_editor.php | 4 ++ templates/Froxlor/login/enter2fa.html.twig | 8 +++ templates/Froxlor/table/macros.html.twig | 10 +++ templates/Froxlor/table/table.html.twig | 2 + 21 files changed, 201 insertions(+), 55 deletions(-) diff --git a/index.php b/index.php index 205b051726..dd3f267376 100644 --- a/index.php +++ b/index.php @@ -72,6 +72,7 @@ exit(); } $code = Request::post('2fa_code'); + $remember = Request::post('2fa_remember'); // verify entered code $tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname')); // get user-data @@ -105,13 +106,6 @@ $userinfo['adminsession'] = $isadmin; $userinfo['userid'] = $uid; - // if not successful somehow - start again - if (!finishLogin($userinfo)) { - Response::redirectTo('index.php', [ - 'showmessage' => '2' - ]); - } - // when using email-2fa, remove the one-time-code if ($userinfo['type_2fa'] == '1') { $del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid"); @@ -119,6 +113,42 @@ 'uid' => $uid ]); } + + // when remember is activated, set the cookie + if ($remember) { + $selector = base64_encode(Froxlor::genSessionId(9)); + $authenticator = Froxlor::genSessionId(33); + $valid_until = time()+60*60*24*30; + $ins_stmt = Database::prepare(" + INSERT INTO `".TABLE_PANEL_2FA_TOKENS."` SET + `selector` = :selector, + `token` = :authenticator, + `userid` = :userid, + `valid_until` = :valid_until + "); + Database::pexecute($ins_stmt, [ + 'selector' => $selector, + 'authenticator' => hash('sha256', $authenticator), + 'userid' => $uid, + 'valid_until' => $valid_until + ]); + $cookie_params = [ + 'expires' => $valid_until, // 30 days + 'path' => '/', + 'domain' => UI::getCookieHost(), + 'secure' => UI::requestIsHttps(), + 'httponly' => true, + 'samesite' => 'Strict' + ]; + setcookie('frx_2fa_remember', $selector.':'.base64_encode($authenticator), $cookie_params); + } + + // if not successful somehow - start again + if (!finishLogin($userinfo)) { + Response::redirectTo('index.php', [ + 'showmessage' => '2' + ]); + } exit(); } // wrong 2fa code - treat like "wrong password" @@ -349,6 +379,22 @@ // 2FA activated if (Settings::Get('2fa.enabled') == '1' && $userinfo['type_2fa'] > 0) { + + // check for remember cookie + if (!empty($_COOKIE['frx_2fa_remember'])) { + list($selector, $authenticator) = explode(':', $_COOKIE['frx_2fa_remember']); + $sel_stmt = Database::prepare("SELECT `token` FROM `".TABLE_PANEL_2FA_TOKENS."` WHERE `selector` = :selector AND `userid` = :uid AND `valid_until` >= UNIX_TIMESTAMP()"); + $token_check = Database::pexecute_first($sel_stmt, ['selector' => $selector, 'uid' => $userinfo[$uid]]); + if ($token_check && hash_equals($token_check['token'], hash('sha256', base64_decode($authenticator)))) { + if (!finishLogin($userinfo)) { + Response::redirectTo('index.php', [ + 'showmessage' => '2' + ]); + } + exit(); + } + } + // redirect to code-enter-page $_SESSION['secret_2fa'] = ($userinfo['type_2fa'] == 2 ? $userinfo['data_2fa'] : 'email'); $_SESSION['uid_2fa'] = $userinfo[$uid]; @@ -829,8 +875,8 @@ function finishLogin($userinfo) $theme = $userinfo['theme']; } else { $theme = Settings::Get('panel.default_theme'); - CurrentUser::setField('theme', $theme); } + CurrentUser::setField('theme', $theme); $qryparams = []; if (!empty($_SESSION['lastqrystr'])) { diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 299560de0f..5ffdb4a639 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -730,8 +730,8 @@ ('panel', 'logo_overridecustom', '0'), ('panel', 'settings_mode', '0'), ('panel', 'menu_collapsed', '1'), - ('panel', 'version', '2.2.0-rc1'), - ('panel', 'db_version', '202401090'); + ('panel', 'version', '2.2.0-rc2'), + ('panel', 'db_version', '202407200'); DROP TABLE IF EXISTS `panel_tasks`; @@ -1049,4 +1049,15 @@ `allowed_from` text NOT NULL, UNIQUE KEY `loginname` (`loginname`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + + +DROP TABLE IF EXISTS `panel_2fa_tokens`; +CREATE TABLE `panel_2fa_tokens` ( + `id` int(11) NOT NULL auto_increment, + `selector` varchar(20) NOT NULL, + `token` varchar(200) NOT NULL, + `userid` int(11) NOT NULL default '0', + `valid_until` int(15) NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; FROXLORSQL; diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index 9e96a98a1d..46645b5e1b 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -122,3 +122,26 @@ Update::showUpdateStep("Updating from 2.2.0-dev1 to 2.2.0-rc1", false); Froxlor::updateToVersion('2.2.0-rc1'); } + +if (Froxlor::isDatabaseVersion('202401090')) { + + Update::showUpdateStep("Adding new table for 2fa tokens"); + Database::query("DROP TABLE IF EXISTS `panel_2fa_tokens`;"); + $sql = "CREATE TABLE `panel_2fa_tokens` ( + `id` int(11) NOT NULL auto_increment, + `selector` varchar(20) NOT NULL, + `token` varchar(200) NOT NULL, + `userid` int(11) NOT NULL default '0', + `valid_until` int(15) NOT NULL, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; + Database::query($sql); + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202407200'); +} + +if (Froxlor::isFroxlorVersion('2.2.0-rc1')) { + Update::showUpdateStep("Updating from 2.2.0-rc1 to 2.2.0-rc2", false); + Froxlor::updateToVersion('2.2.0-rc2'); +} diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 60e81f5974..c52d6dc56a 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -270,15 +270,6 @@ public function update() throw new Exception("You cannot access this resource", 405); } - // if enabling catchall is not allowed by settings, we do not need - // to run update() - if (Settings::Get('catchall.catchall_enabled') != '1') { - Response::standardError([ - 'operationnotpermitted', - 'featureisdisabled' - ], 'catchall', true); - } - $id = $this->getParam('id', true, 0); $ea_optional = $id > 0; $emailaddr = $this->getParam('emailaddr', $ea_optional, ''); @@ -297,30 +288,41 @@ public function update() $iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']); $description = $this->getParam('description', true, $result['description']); + // if enabling catchall is not allowed by settings, we do not need + // to run update() + if ($iscatchall && $result['iscatchall'] == 0 && Settings::Get('catchall.catchall_enabled') != '1') { + Response::standardError([ + 'operationnotpermitted', + 'featureisdisabled' + ], 'catchall', true); + } + // get needed customer info to reduce the email-address-counter by one $customer = $this->getCustomerData(); // check for catchall-flag + $email = $result['email_full']; if ($iscatchall) { $iscatchall = '1'; - $email_parts = explode('@', $result['email_full']); - $email = '@' . $email_parts[1]; - // catchall check - $stmt = Database::prepare(" - SELECT `email_full` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `email` = :email AND `customerid` = :cid AND `iscatchall` = '1' - "); - $params = [ - "email" => $email, - "cid" => $customer['customerid'] - ]; - $email_check = Database::pexecute_first($stmt, $params, true, true); - if ($email_check) { - Response::standardError('youhavealreadyacatchallforthisdomain', '', true); + $email = $result['email']; + // update only required if it was not a catchall before + if ($result['iscatchall'] == 0) { + $email_parts = explode('@', $result['email_full']); + $email = '@' . $email_parts[1]; + // catchall check + $stmt = Database::prepare(" + SELECT `email_full` FROM `" . TABLE_MAIL_VIRTUAL . "` + WHERE `email` = :email AND `customerid` = :cid AND `iscatchall` = '1' + "); + $params = [ + "email" => $email, + "cid" => $customer['customerid'] + ]; + $email_check = Database::pexecute_first($stmt, $params, true, true); + if ($email_check) { + Response::standardError('youhavealreadyacatchallforthisdomain', '', true); + } } - } else { - $iscatchall = '0'; - $email = $result['email_full']; } $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true); diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index 6c796234c0..1c4870c202 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -983,9 +983,11 @@ public function listing() '`d`.`letsencrypt`', '`d`.`registration_date`', '`d`.`termination_date`', - '`d`.`deactivated`' + '`d`.`deactivated`', + '`d`.`email_only`', ]; } + $query_fields = []; // prepare select statement @@ -996,7 +998,6 @@ public function listing() LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id` LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid` WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") - AND `d`.`email_only` = '0' " . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit()); $result = []; @@ -1092,13 +1093,13 @@ public function listingCount() $this->getUserDetail('customerid') ]; } + if (!empty($customer_ids)) { // prepare select statement $domains_stmt = Database::prepare(" SELECT COUNT(*) as num_subdom FROM `" . TABLE_PANEL_DOMAINS . "` `d` WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") - AND `d`.`email_only` = '0' "); $result = Database::pexecute_first($domains_stmt, null, true, true); if ($result) { diff --git a/lib/Froxlor/Cli/MasterCron.php b/lib/Froxlor/Cli/MasterCron.php index 61926ecc10..7045de8ec4 100644 --- a/lib/Froxlor/Cli/MasterCron.php +++ b/lib/Froxlor/Cli/MasterCron.php @@ -171,8 +171,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int FroxlorLogger::getInstanceOf()->setCronLog(0); } - // clean up possible old login-links + // clean up possible old login-links and 2fa tokens Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()"); + Database::query("DELETE FROM `" . TABLE_PANEL_2FA_TOKENS . "` WHERE `valid_until` < UNIX_TIMESTAMP()"); return $result; } diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index a8ca8771c0..b49a7e22a7 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -54,7 +54,7 @@ public static function getAllowedDomainEntry(int $domain_id, string $area = 'cus $dom_data['uid'] = $userinfo['userid']; } } else { - $where_clause = '`customerid` = :uid AND '; + $where_clause = '`customerid` = :uid AND `email_only` = "0" AND '; $dom_data['uid'] = $userinfo['userid']; } diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 83bc550119..0a5011e37e 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -31,10 +31,10 @@ final class Froxlor { // Main version variable - const VERSION = '2.2.0-rc1'; + const VERSION = '2.2.0-rc2'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202401090'; + const DBVERSION = '202407200'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/Froxlor/UI/Callbacks/Domain.php b/lib/Froxlor/UI/Callbacks/Domain.php index b8fb3f68dd..f635ae2584 100644 --- a/lib/Froxlor/UI/Callbacks/Domain.php +++ b/lib/Froxlor/UI/Callbacks/Domain.php @@ -74,6 +74,9 @@ public static function domainTarget(array $attributes) if ($attributes['fields']['deactivated']) { return lng('admin.deactivated'); } + if ($attributes['fields']['email_only']) { + return lng('domains.email_only'); + } // path or redirect if (preg_match('/^https?\:\/\//', $attributes['fields']['documentroot'])) { return [ @@ -127,7 +130,7 @@ public static function canEdit(array $attributes): bool public static function canViewLogs(array $attributes): bool { - if ((!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0)) && !$attributes['fields']['deactivated']) { + if ((int)$attributes['fields']['email_only'] == 0 && !$attributes['fields']['deactivated']) { if ((int)UI::getCurrentUser()['adminsession'] == 0 && (bool)UI::getCurrentUser()['logviewenabled']) { return true; } elseif ((int)UI::getCurrentUser()['adminsession'] == 1) { @@ -157,6 +160,7 @@ public static function canEditDNS(array $attributes): bool && $attributes['fields']['caneditdomain'] == '1' && Settings::Get('system.bind_enable') == '1' && Settings::Get('system.dnsenabled') == '1' + && !$attributes['fields']['email_only'] && !$attributes['fields']['deactivated']; } @@ -169,7 +173,7 @@ public static function adminCanEditDNS(array $attributes): bool public static function hasLetsEncryptActivated(array $attributes): bool { - return ((bool)$attributes['fields']['letsencrypt'] && (!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0))); + return ((bool)$attributes['fields']['letsencrypt'] && (int)$attributes['fields']['email_only'] == 0); } /** @@ -181,7 +185,7 @@ public static function canEditSSL(array $attributes): bool && DDomain::domainHasSslIpPort($attributes['fields']['id']) && (CurrentUser::isAdmin() || (!CurrentUser::isAdmin() && (int)$attributes['fields']['caneditdomain'] == 1)) && (int)$attributes['fields']['letsencrypt'] == 0 - && (!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0)) + && !(int)$attributes['fields']['email_only'] && !$attributes['fields']['deactivated'] ) { return true; diff --git a/lib/Froxlor/UI/Callbacks/Text.php b/lib/Froxlor/UI/Callbacks/Text.php index 91df6fdf7d..c1a8cbef2c 100644 --- a/lib/Froxlor/UI/Callbacks/Text.php +++ b/lib/Froxlor/UI/Callbacks/Text.php @@ -52,6 +52,14 @@ public static function yesno(array $attributes): array ]; } + public static function type2fa(array $attributes): array + { + return [ + 'macro' => 'type2fa', + 'data' => (int)$attributes['data'] + ]; + } + public static function customerfullname(array $attributes): string { return User::getCorrectFullUserDetails($attributes['fields'], true); diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index 47dde7bb6a..6e0ab1cc12 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -47,13 +47,14 @@ 'values' => $domainips ], 'alias' => [ - 'visible' => $alias_check == '0', + 'visible' => $alias_check == '0' && (int)$result['email_only'] == 0, 'label' => lng('domains.aliasdomain'), 'type' => 'select', 'select_var' => $domains, 'selected' => $result['aliasdomain'] ], 'path' => [ + 'visible' => (int)$result['email_only'] == 0, 'label' => lng('panel.path'), 'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null), 'type' => $pathSelect['type'], @@ -63,13 +64,13 @@ 'note' => $pathSelect['note'] ?? '', ], 'url' => [ - 'visible' => Settings::Get('panel.pathedit') == 'Dropdown', + 'visible' => Settings::Get('panel.pathedit') == 'Dropdown' && (int)$result['email_only'] == 0, 'label' => lng('panel.urloverridespath'), 'type' => 'text', 'value' => $urlvalue ], 'redirectcode' => [ - 'visible' => Settings::Get('customredirect.enabled') == '1', + 'visible' => Settings::Get('customredirect.enabled') == '1' && (int)$result['email_only'] == 0, 'label' => lng('domains.redirectifpathisurl'), 'desc' => lng('domains.redirectifpathisurlinfo'), 'type' => 'select', @@ -77,7 +78,7 @@ 'selected' => $def_code ], 'selectserveralias' => [ - 'visible' => ($result['parentdomainid'] == '0' && $userinfo['subdomains'] != '0') || $result['parentdomainid'] != '0', + 'visible' => (($result['parentdomainid'] == '0' && $userinfo['subdomains'] != '0') || $result['parentdomainid'] != '0') && (int)$result['email_only'] == 0, 'label' => lng('admin.selectserveralias'), 'desc' => lng('admin.selectserveralias_desc'), 'type' => 'select', @@ -85,27 +86,28 @@ 'selected' => $serveraliasoptions_selected ], 'isemaildomain' => [ - 'visible' => ($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2') && $result['parentdomainid'] != '0', + 'visible' => (($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2') && $result['parentdomainid'] != '0') && (int)$result['email_only'] == 0, 'label' => 'Emaildomain', 'type' => 'checkbox', 'value' => '1', 'checked' => $result['isemaildomain'] ], 'openbasedir_path' => [ - 'visible' => $result['openbasedir'] == '1', + 'visible' => $result['openbasedir'] == '1' && (int)$result['email_only'] == 0, 'label' => lng('domain.openbasedirpath'), 'type' => 'select', 'select_var' => $openbasedir, 'selected' => $result['openbasedir_path'] ], 'phpsettingid' => [ - 'visible' => ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && count($phpconfigs) > 0 && $userinfo['phpenabled'] == '1' && $result['phpenabled'] == '1', + 'visible' => ((int)Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && count($phpconfigs) > 0 && $userinfo['phpenabled'] == '1' && $result['phpenabled'] == '1' && (int)$result['email_only'] == 0, 'label' => lng('admin.phpsettings.title'), 'type' => 'select', 'select_var' => $phpconfigs, 'selected' => $result['phpsettingid'] ], 'speciallogfile' => [ + 'visible' => (int)$result['email_only'] == 0, 'label' => lng('admin.speciallogfile.title'), 'desc' => lng('admin.speciallogfile.description'), 'type' => 'checkbox', @@ -139,7 +141,7 @@ 'section_bssl' => [ 'title' => lng('admin.webserversettings_ssl'), 'image' => 'icons/domain_edit.png', - 'visible' => Settings::Get('system.use_ssl') == '1' && $ssl_ipsandports && Domain::domainHasSslIpPort($result['id']), + 'visible' => Settings::Get('system.use_ssl') == '1' && $ssl_ipsandports && Domain::domainHasSslIpPort($result['id']) && (int)$result['email_only'] == 0, 'fields' => [ 'sslenabled' => [ 'label' => lng('admin.domain_sslenabled'), @@ -194,6 +196,7 @@ ] ] ] - ] + ], + 'buttons' => ((int)$result['email_only'] == 1) ? [] : null ] ]; diff --git a/lib/tablelisting/admin/tablelisting.admins.php b/lib/tablelisting/admin/tablelisting.admins.php index 637f3d4c4b..7af1eec389 100644 --- a/lib/tablelisting/admin/tablelisting.admins.php +++ b/lib/tablelisting/admin/tablelisting.admins.php @@ -110,6 +110,12 @@ 'class' => 'text-center', 'callback' => [Text::class, 'boolean'], ], + 'type_2fa' => [ + 'label' => lng('2fa.type_2fa'), + 'field' => 'type_2fa', + 'class' => 'text-center', + 'callback' => [Text::class, 'type2fa'], + ], ], 'visible_columns' => Listing::getVisibleColumnsForListing('admin_list', [ 'loginname', diff --git a/lib/tablelisting/admin/tablelisting.customers.php b/lib/tablelisting/admin/tablelisting.customers.php index de3e8fb503..6c1c7979e2 100644 --- a/lib/tablelisting/admin/tablelisting.customers.php +++ b/lib/tablelisting/admin/tablelisting.customers.php @@ -149,6 +149,12 @@ 'class' => 'text-center', 'callback' => [Text::class, 'boolean'], ], + 'c.type_2fa' => [ + 'label' => lng('2fa.type_2fa'), + 'field' => 'type_2fa', + 'class' => 'text-center', + 'callback' => [Text::class, 'type2fa'], + ], ], 'visible_columns' => Listing::getVisibleColumnsForListing('customer_list', [ 'c.name', diff --git a/lib/tables.inc.php b/lib/tables.inc.php index 26214333d5..0805f29064 100644 --- a/lib/tables.inc.php +++ b/lib/tables.inc.php @@ -57,3 +57,4 @@ const TABLE_API_KEYS = 'api_keys'; const TABLE_PANEL_USERCOLUMNS = 'panel_usercolumns'; const TABLE_PANEL_LOGINLINKS = 'panel_loginlinks'; +const TABLE_PANEL_2FA_TOKENS = 'panel_2fa_tokens'; diff --git a/lng/de.lng.php b/lng/de.lng.php index 8a3eb506ba..167cf8eebe 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -48,6 +48,7 @@ '2fa_ga_desc' => 'Das Konto ist eingerichtet, um zeitbasierte Einmalpasswörter via Authenticator-App zu erhalten. Um die gewünschte Authenticator-App einzurichten, scanne bitte den untenstehenden QR-Code. Zum Deaktivieren, klicke auf "2FA deaktivieren"', '2fa_not_activated' => 'Zwei-Faktor Authentifizierung ist nicht aktiviert', '2fa_not_activated_for_user' => 'Zwei-Faktor Authentifizierung ist für den aktuellen Benutzer nicht aktiviert', + 'type_2fa' => '2FA Status', ], 'admin' => [ 'overview' => 'Übersicht', @@ -713,6 +714,7 @@ 'hsts' => 'HSTS aktiviert', 'aliasdomainid' => 'ID der Alias-Domain', 'nodomainsassignedbyadmin' => 'Diesem Account wurde noch keine (aktive) Domain zugewiesen. Bitte kontaktiere deinen Administrator, wenn du der Meinung bist, das ist nicht korrekt.', + 'email_only' => 'Nur E-Mail', ], 'emails' => [ 'description' => 'Hier können Sie Ihre E-Mail-Adressen einrichten.
Ein Konto ist wie Ihr Briefkasten vor der Haustür. Wenn jemand eine E-Mail an Sie schreibt, wird diese in dieses Konto gelegt.

Die Zugangsdaten lauten wie folgt: (Die Angaben in kursiver Schrift sind durch die jeweiligen Einträge zu ersetzen)

Hostname: Domainname
Benutzername: Kontoname / E-Mail-Adresse
Passwort: das gewählte Passwort', @@ -1031,6 +1033,7 @@ 'combination_not_found' => 'Kombination aus Benutzername und E-Mail Adresse stimmen nicht überein.', '2fa' => 'Zwei-Faktor Authentifizierung (2FA)', '2facode' => 'Bitte 2FA Code angeben', + '2faremember' => 'Browser vertrauen', ], 'mails' => [ 'pop_success' => [ diff --git a/lng/en.lng.php b/lng/en.lng.php index 112686c709..d51a45064c 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -49,6 +49,7 @@ '2fa_ga_desc' => 'Your account is set up to use time-based one-time passwords via authenticator-app. Please scan the QR code below with your desired authenticator app to generate the codes. To deactivate, click on "Deactivate 2FA"', '2fa_not_activated' => 'Two-factor authentication is not enabled', '2fa_not_activated_for_user' => 'Two-factor authentication is not enabled for the current user', + 'type_2fa' => '2FA status', ], 'admin' => [ 'overview' => 'Overview', @@ -784,6 +785,7 @@ 'hsts' => 'HSTS enabled', 'aliasdomainid' => 'ID of alias domain', 'nodomainsassignedbyadmin' => 'Your account has currently no (active) domains assigned to it. Please contact your administrator if you think this is wrong.', + 'email_only' => 'Email only', ], 'emails' => [ 'description' => 'Here you can create and change your email addresses.
An account is like your letterbox in front of your house. If someone sends you an email, it will be dropped into the account.

To download your emails use the following settings in your mailprogram: (The data in italics has to be changed to the equivalents you typed in!)
Hostname: domainname
Username: account name / e-mail address
password: the password you\'ve chosen', @@ -1103,6 +1105,7 @@ 'combination_not_found' => 'Combination of user and email address not found.', '2fa' => 'Two-factor authentication (2FA)', '2facode' => 'Please enter 2FA code', + '2faremember' => 'Trust browser', ], 'mails' => [ 'pop_success' => [ diff --git a/logfiles_viewer.php b/logfiles_viewer.php index 20d00d7c4c..e3a65872fa 100644 --- a/logfiles_viewer.php +++ b/logfiles_viewer.php @@ -61,6 +61,10 @@ } $domain = json_decode($json_result, true)['data']; + if ($domain['email_only']) { + Response::dynamicError("There are no webserver logfiles for email only domains."); + } + $speciallogfile = ''; if ($domain['speciallogfile'] == '1') { if ($domain['parentdomainid'] == '0') { diff --git a/ssl_editor.php b/ssl_editor.php index b0d1c77051..8fea36d945 100644 --- a/ssl_editor.php +++ b/ssl_editor.php @@ -50,6 +50,10 @@ } $result_domain = json_decode($json_result, true)['data']; + if ($result_domain['email_only']) { + Response::dynamicError("There are no ssl-certificates for email only domains."); + } + if (Request::post('send') == 'send') { $do_insert = Request::post('do_insert', 0) == 1; try { diff --git a/templates/Froxlor/login/enter2fa.html.twig b/templates/Froxlor/login/enter2fa.html.twig index b435bb0b55..37cc3d6687 100644 --- a/templates/Froxlor/login/enter2fa.html.twig +++ b/templates/Froxlor/login/enter2fa.html.twig @@ -22,6 +22,14 @@ +
+
+ + + +
+
+
diff --git a/templates/Froxlor/table/macros.html.twig b/templates/Froxlor/table/macros.html.twig index 3a8e49106b..c5cdab920c 100644 --- a/templates/Froxlor/table/macros.html.twig +++ b/templates/Froxlor/table/macros.html.twig @@ -29,6 +29,16 @@ {% endif %} {% endmacro %} +{% macro type2fa(data) %} + {% if (data == 1) %} + + {% elseif (data == 2) %} + + {% else %} + + {% endif %} +{% endmacro %} + {% macro link(data) %} {% apply spaceless %} diff --git a/templates/Froxlor/table/table.html.twig b/templates/Froxlor/table/table.html.twig index 3c4384cb58..578dad3f90 100644 --- a/templates/Froxlor/table/table.html.twig +++ b/templates/Froxlor/table/table.html.twig @@ -47,6 +47,8 @@ {{ macros.domainWithSan(td.data.data) }} {% elseif td.data.macro == 'actions' %} {{ macros.actions(td.data.data) }} + {% elseif td.data.macro == 'type2fa' %} + {{ macros.type2fa(td.data.data) }} {% else %} Table macro '{{ td.data.macro|json_encode }}' is not implemented! Unable to handle this data: {{ td.data|json_encode }}