From c1f03c1683c7a43f0bb1797dbc3e88c240f3bdf9 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 23 May 2023 14:36:45 +0200 Subject: [PATCH 01/26] remove 'main but subdomain' as we now automatically create the correct order of vhost configs and dns zones Signed-off-by: Michael Kaufmann --- admin_domains.php | 48 ++-------------- install/froxlor.sql.php | 1 - install/updates/froxlor/update_2.x.inc.php | 8 +++ lib/Froxlor/Api/Commands/Domains.php | 55 ++----------------- lib/Froxlor/Cron/Dns/Bind.php | 6 +- lib/Froxlor/Cron/Dns/DnsBase.php | 24 ++++---- lib/Froxlor/Cron/Dns/PowerDNS.php | 6 +- lib/Froxlor/Cron/Http/Apache.php | 23 -------- lib/Froxlor/Cron/Http/HttpConfigBase.php | 15 +++++ lib/Froxlor/Cron/Http/Lighttpd.php | 21 +------ lib/Froxlor/Cron/Http/Nginx.php | 20 ------- lib/Froxlor/Domain/Domain.php | 49 +++++------------ .../admin/domains/formfield.domains_add.php | 6 -- .../admin/domains/formfield.domains_edit.php | 7 --- lng/de.lng.php | 4 -- lng/en.lng.php | 4 -- lng/es.lng.php | 4 -- lng/it.lng.php | 4 -- lng/nl.lng.php | 4 -- 19 files changed, 70 insertions(+), 239 deletions(-) diff --git a/admin_domains.php b/admin_domains.php index 59755968..c295387c 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -114,15 +114,11 @@ if ($page == 'domains' || $page == 'overview') { } elseif ($alias_check['count'] > 0) { Response::standardError('domains_cantdeletedomainwithaliases'); } else { - $showcheck = false; - if (Domain::domainHasMainSubDomains($id)) { - $showcheck = true; - } - HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'remove_subbutmain_domains', $filename, [ + HTML::askYesNo('admin_domain_reallydelete', $filename, [ 'id' => $id, 'page' => $page, 'action' => $action - ], $idna_convert->decode($result['domain']), $showcheck); + ], $idna_convert->decode($result['domain'])); } } } elseif ($action == 'add') { @@ -252,21 +248,6 @@ if ($page == 'domains' || $page == 'overview') { $domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')'; } - $subtodomains = [ - 0 => lng('domains.nosubtomaindomain') - ]; - $result_domains_stmt = Database::prepare(" - SELECT `d`.`id`, `d`.`domain`, `c`.`loginname` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c` - WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = 0 AND `d`.`ismainbutsubto` = 0 " . $standardsubdomains . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . " - AND `d`.`customerid`=`c`.`customerid` ORDER BY `loginname`, `domain` ASC - "); - // params from above still valid - Database::pexecute($result_domains_stmt, $params); - - while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) { - $subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']) . ' (' . $row_domain['loginname'] . ')'; - } - $phpconfigs = []; $configs = Database::query(" SELECT c.*, fc.description as interpreter @@ -287,7 +268,7 @@ if ($page == 'domains' || $page == 'overview') { 1 => lng('domain.homedir'), 2 => lng('domain.docparent') ]; - + // create serveralias options $serveraliasoptions = [ 0 => lng('domains.serveraliasoption_wildcard'), @@ -469,27 +450,6 @@ if ($page == 'domains' || $page == 'overview') { $domains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']); } - $subtodomains = [ - 0 => lng('domains.nosubtomaindomain') - ]; - $result_domains_stmt = Database::prepare(" - SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c` - WHERE `d`.`aliasdomain` IS NULL AND `d`.`parentdomainid` = '0' AND `d`.`id` <> :id - AND `c`.`standardsubdomain`<>`d`.`id` AND `c`.`customerid`=`d`.`customerid`" . ($userinfo['customers_see_all'] ? '' : " AND `d`.`adminid` = :adminid") . " - ORDER BY `d`.`domain` ASC - "); - $params = [ - 'id' => $result['id'] - ]; - if ($userinfo['customers_see_all'] == '0') { - $params['adminid'] = $userinfo['adminid']; - } - Database::pexecute($result_domains_stmt, $params); - - while ($row_domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) { - $subtodomains[$row_domain['id']] = $idna_convert->decode($row_domain['domain']); - } - if ($userinfo['ip'] == "-1") { $result_ipsandports_stmt = Database::query(" SELECT `id`, `ip`, `port` FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `ssl`='0' ORDER BY `ip`, `port` ASC @@ -556,7 +516,7 @@ if ($page == 'domains' || $page == 'overview') { 1 => lng('domain.homedir'), 2 => lng('domain.docparent') ]; - + $serveraliasoptions = [ 0 => lng('domains.serveraliasoption_wildcard'), 1 => lng('domains.serveraliasoption_www'), diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 62c626f2..8b680cfe 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -278,7 +278,6 @@ CREATE TABLE `panel_domains` ( `phpsettingid` INT( 11 ) UNSIGNED NOT NULL DEFAULT '1', `mod_fcgid_starter` int(4) default '-1', `mod_fcgid_maxrequests` int(4) default '-1', - `ismainbutsubto` int(11) unsigned NOT NULL default '0', `letsencrypt` tinyint(1) NOT NULL default '0', `hsts` varchar(10) NOT NULL default '0', `hsts_sub` tinyint(1) NOT NULL default '0', diff --git a/install/updates/froxlor/update_2.x.inc.php b/install/updates/froxlor/update_2.x.inc.php index 228fdac1..5c035172 100644 --- a/install/updates/froxlor/update_2.x.inc.php +++ b/install/updates/froxlor/update_2.x.inc.php @@ -492,3 +492,11 @@ if (Froxlor::isFroxlorVersion('2.0.18')) { Update::showUpdateStep("Updating from 2.0.18 to 2.0.19", false); Froxlor::updateToVersion('2.0.19'); } + +if (Froxlor::isDatabaseVersion('202304260')) { + Update::showUpdateStep("Cleaning domains table"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;"); + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202305231'); +} diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index ea318e97..ab81efd5 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -190,9 +190,6 @@ class Domains extends ApiCommand implements ResourceEntity * optional, whether to create an exclusive web-logfile for this domain, default 0 (false) * @param int $alias * optional, domain-id of a domain that the new domain should be an alias of, default 0 (none) - * @param int $issubof - * optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to - * generate the correct order), default 0 (none) * @param string $registration_date * optional, date of domain registration in form of YYYY-MM-DD, default empty (none) * @param string $termination_date @@ -298,7 +295,6 @@ class Domains extends ApiCommand implements ResourceEntity $serveraliasoption = $this->getParam('selectserveralias', true, Settings::Get('system.domaindefaultalias')); $speciallogfile = $this->getBoolParam('speciallogfile', true, 0); $aliasdomain = intval($this->getParam('alias', true, 0)); - $issubof = $this->getParam('issubof', true, 0); $registration_date = $this->getParam('registration_date', true, ''); $termination_date = $this->getParam('termination_date', true, ''); $caneditdomain = $this->getBoolParam('caneditdomain', true, 0); @@ -665,10 +661,6 @@ class Domains extends ApiCommand implements ResourceEntity $serveraliasoption = '0'; } - if ($issubof <= 0) { - $issubof = '0'; - } - $idna_convert = new IdnaWrapper(); if ($domain == '') { Response::standardError([ @@ -723,7 +715,6 @@ class Domains extends ApiCommand implements ResourceEntity 'phpsettingid' => $phpsettingid, 'mod_fcgid_starter' => $mod_fcgid_starter, 'mod_fcgid_maxrequests' => $mod_fcgid_maxrequests, - 'ismainbutsubto' => $issubof, 'letsencrypt' => $letsencrypt, 'http2' => $http2, 'hsts' => $hsts_maxage, @@ -777,7 +768,6 @@ class Domains extends ApiCommand implements ResourceEntity `phpsettingid` = :phpsettingid, `mod_fcgid_starter` = :mod_fcgid_starter, `mod_fcgid_maxrequests` = :mod_fcgid_maxrequests, - `ismainbutsubto` = :ismainbutsubto, `letsencrypt` = :letsencrypt, `http2` = :http2, `hsts` = :hsts, @@ -1069,9 +1059,6 @@ class Domains extends ApiCommand implements ResourceEntity * default 0 (false) * @param int $alias * optional, domain-id of a domain that the new domain should be an alias of, default 0 (none) - * @param int $issubof - * optional, domain-id of a domain this domain is a subdomain of (required for webserver-cronjob to - * generate the correct order), default 0 (none) * @param string $registration_date * optional, date of domain registration in form of YYYY-MM-DD, default empty (none) * @param string $termination_date @@ -1191,7 +1178,6 @@ class Domains extends ApiCommand implements ResourceEntity $speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']); $speciallogverified = $this->getBoolParam('speciallogverified', true, 0); $aliasdomain = intval($this->getParam('alias', true, $result['aliasdomain'])); - $issubof = $this->getParam('issubof', true, $result['ismainbutsubto']); $registration_date = $this->getParam('registration_date', true, $result['registration_date']); $termination_date = $this->getParam('termination_date', true, $result['termination_date']); $caneditdomain = $this->getBoolParam('caneditdomain', true, $result['caneditdomain']); @@ -1640,10 +1626,6 @@ class Domains extends ApiCommand implements ResourceEntity Response::standardError('domainisaliasorothercustomer', '', true); } - if ($issubof <= 0) { - $issubof = '0'; - } - if ($serveraliasoption != '1' && $serveraliasoption != '2') { $serveraliasoption = '0'; } @@ -1666,7 +1648,6 @@ class Domains extends ApiCommand implements ResourceEntity || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] - || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] @@ -1837,7 +1818,6 @@ class Domains extends ApiCommand implements ResourceEntity $update_data['writeerrorlog'] = $writeerrorlog; $update_data['registration_date'] = $registration_date; $update_data['termination_date'] = $termination_date; - $update_data['ismainbutsubto'] = $issubof; $update_data['letsencrypt'] = $letsencrypt; $update_data['http2'] = $http2; $update_data['hsts'] = $hsts_maxage; @@ -1885,7 +1865,6 @@ class Domains extends ApiCommand implements ResourceEntity `writeerrorlog` = :writeerrorlog, `registration_date` = :registration_date, `termination_date` = :termination_date, - `ismainbutsubto` = :ismainbutsubto, `letsencrypt` = :letsencrypt, `http2` = :http2, `hsts` = :hsts, @@ -2073,9 +2052,6 @@ class Domains extends ApiCommand implements ResourceEntity * optional, the domain-id * @param string $domainname * optional, the domainname - * @param bool $delete_mainsubdomains - * optional, remove also domains that are subdomains of this domain but added as main domains; default - * false * @param bool $is_stdsubdomain * optional, default false, specify whether it's a std-subdomain you are deleting as it does not count * as subdomain-resource @@ -2091,7 +2067,6 @@ class Domains extends ApiCommand implements ResourceEntity $dn_optional = $id > 0; $domainname = $this->getParam('domainname', $dn_optional, ''); $is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0); - $remove_subbutmain_domains = $this->getParam('delete_mainsubdomains', true, 0); $result = $this->apiCall('Domains.get', [ 'id' => $id, @@ -2099,15 +2074,10 @@ class Domains extends ApiCommand implements ResourceEntity ]); $id = $result['id']; - // check for deletion of main-domains which are logically subdomains, #329 - $rsd_sql = ''; - if ($remove_subbutmain_domains) { - $rsd_sql .= " OR `ismainbutsubto` = :id"; - } - $subresult_stmt = Database::prepare(" - SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE (`id` = :id OR `parentdomainid` = :id " . $rsd_sql . ")"); + SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` + WHERE (`id` = :id OR `parentdomainid` = :id) + "); Database::pexecute($subresult_stmt, [ 'id' => $id ], true, true); @@ -2129,23 +2099,10 @@ class Domains extends ApiCommand implements ResourceEntity $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] deleted domain/s from mail-tables"); } - // if mainbutsubto-domains are not to be deleted, re-assign the (ismainbutsubto value of the main - // domain which is being deleted) as their new ismainbutsubto value - if ($remove_subbutmain_domains !== 1) { - $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_DOMAINS . "` SET - `ismainbutsubto` = :newIsMainButSubtoValue - WHERE `ismainbutsubto` = :deletedMainDomainId - "); - Database::pexecute($upd_stmt, [ - 'newIsMainButSubtoValue' => $result['ismainbutsubto'], - 'deletedMainDomainId' => $id - ], true, true); - } - $del_stmt = Database::prepare(" - DELETE FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE `id` = :id OR `parentdomainid` = :id " . $rsd_sql); + DELETE FROM `" . TABLE_PANEL_DOMAINS . "` + WHERE `id` = :id OR `parentdomainid` = :id + "); Database::pexecute($del_stmt, [ 'id' => $id ], true, true); diff --git a/lib/Froxlor/Cron/Dns/Bind.php b/lib/Froxlor/Cron/Dns/Bind.php index 939796d7..882b3d99 100644 --- a/lib/Froxlor/Cron/Dns/Bind.php +++ b/lib/Froxlor/Cron/Dns/Bind.php @@ -62,8 +62,8 @@ class Bind extends DnsBase $this->bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n"; foreach ($domains as $domain) { - if ($domain['ismainbutsubto'] > 0) { - // domains with ismainbutsubto>0 are handled by recursion within walkDomainList() + if ($domain['is_child']) { + // domains that are subdomains to other main domains are handled by recursion within walkDomainList() continue; } $this->walkDomainList($domain, $domains); @@ -114,7 +114,7 @@ class Bind extends DnsBase $isFroxlorHostname = true; } - if ($domain['ismainbutsubto'] == 0) { + if (!$domain['is_child']) { $zoneContent = (string)Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); $domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone'; $zonefile_name = FileDir::makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']); diff --git a/lib/Froxlor/Cron/Dns/DnsBase.php b/lib/Froxlor/Cron/Dns/DnsBase.php index 5c9eb018..f9ceaede 100644 --- a/lib/Froxlor/Cron/Dns/DnsBase.php +++ b/lib/Froxlor/Cron/Dns/DnsBase.php @@ -26,6 +26,7 @@ namespace Froxlor\Cron\Dns; use Froxlor\Database\Database; +use Froxlor\Domain\Domain; use Froxlor\FileDir; use Froxlor\FroxlorLogger; use Froxlor\PhpHelper; @@ -210,7 +211,6 @@ abstract class DnsBase `d`.`dkim`, `d`.`dkim_id`, `d`.`dkim_pubkey`, - `d`.`ismainbutsubto`, `c`.`loginname`, `c`.`guid` FROM @@ -219,7 +219,7 @@ abstract class DnsBase WHERE `d`.`isbinddomain` = '1' ORDER BY - `d`.`domain` ASC + LENGTH(`d`.`domain`), `d`.`domain` ASC "); $domains = []; @@ -241,7 +241,6 @@ abstract class DnsBase 'bindserial' => date('Ymd') . '00', 'dkim' => '0', 'iswildcarddomain' => '1', - 'ismainbutsubto' => '0', 'zonefile' => '', 'froxlorhost' => '1' ]; @@ -257,18 +256,23 @@ abstract class DnsBase if (!isset($domains[$key]['children'])) { $domains[$key]['children'] = []; } - if ($domains[$key]['ismainbutsubto'] > 0) { - if (isset($domains[$domains[$key]['ismainbutsubto']])) { - $domains[$domains[$key]['ismainbutsubto']]['children'][] = $domains[$key]['id']; - } else { - $domains[$key]['ismainbutsubto'] = 0; + if (!isset($domains[$key]['is_child'])) { + $domains[$key]['is_child'] = false; + } + $children = Domain::getMainSubdomainIds($key); + if (count($children) > 0) { + foreach ($children as $child) { + if (isset($domains[$child])) { + $domains[$key]['children'][] = $domains[$child]['id']; + $domains[$child]['is_child'] = true; + } } } } - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . 'ismainbutsubto ' . str_pad('parent domain', 40, ' ') . "list of child domain ids"); + $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . "list of child domain ids"); foreach ($domains as $domain) { - $logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . str_pad($domain['ismainbutsubto'], 15, ' ') . str_pad(((isset($domains[$domain['ismainbutsubto']])) ? $domains[$domain['ismainbutsubto']]['domain'] : '-'), 40, ' ') . join(', ', $domain['children']); + $logLine = str_pad($domain['id'], 9, ' ') . str_pad($domain['domain'], 40, ' ') . join(', ', $domain['children']); $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, $logLine); } diff --git a/lib/Froxlor/Cron/Dns/PowerDNS.php b/lib/Froxlor/Cron/Dns/PowerDNS.php index c3d8f20b..65fb25ca 100644 --- a/lib/Froxlor/Cron/Dns/PowerDNS.php +++ b/lib/Froxlor/Cron/Dns/PowerDNS.php @@ -50,8 +50,8 @@ class PowerDNS extends DnsBase } foreach ($domains as $domain) { - if ($domain['ismainbutsubto'] > 0) { - // domains with ismainbutsubto>0 are handled by recursion within walkDomainList() + if ($domain['is_child']) { + // domains that are subdomains to other main domains are handled by recursion within walkDomainList() continue; } $this->walkDomainList($domain, $domains); @@ -108,7 +108,7 @@ class PowerDNS extends DnsBase $isFroxlorHostname = true; } - if ($domain['ismainbutsubto'] == 0) { + if (!$domain['is_child']) { $zoneContent = Dns::createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); if (count($subzones)) { foreach ($subzones as $subzone) { diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index faa439ef..8fba3764 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -630,29 +630,6 @@ class Apache extends HttpConfigBase } } - /** - * Get the filename for the virtualhost - */ - protected function getVhostFilename($domain, $ssl_vhost = false) - { - if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) { - $vhost_no = '35'; - } elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) { - $vhost_no = '30'; - } else { - // number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth - $vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1); - } - - if ($ssl_vhost === true) { - $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf'); - } else { - $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf'); - } - - return $vhost_filename; - } - /** * We compose the virtualhost entry for one domain */ diff --git a/lib/Froxlor/Cron/Http/HttpConfigBase.php b/lib/Froxlor/Cron/Http/HttpConfigBase.php index 7b400726..4226322a 100644 --- a/lib/Froxlor/Cron/Http/HttpConfigBase.php +++ b/lib/Froxlor/Cron/Http/HttpConfigBase.php @@ -28,6 +28,7 @@ namespace Froxlor\Cron\Http; use Froxlor\Cron\Http\LetsEncrypt\AcmeSh; use Froxlor\Cron\Http\Php\Fpm; use Froxlor\Database\Database; +use Froxlor\Domain\Domain; use Froxlor\FileDir; use Froxlor\Froxlor; use Froxlor\FroxlorLogger; @@ -187,4 +188,18 @@ class HttpConfigBase } return false; } + + /** + * Get the filename for the virtualhost + */ + protected function getVhostFilename(array $domain, bool $ssl_vhost = false, bool $filename_only = false) + { + // number of dots in a domain specifies its position (and depth of subdomain) starting at 35 going downwards on higher depth + $vhost_no = (string)(35 - substr_count($domain['domain'], ".") + 1); + $filename = $vhost_no . '_froxlor_' . ($ssl_vhost ? 'ssl' : 'normal') . '_vhost_' . $domain['domain'] . '.conf'; + if ($filename_only) { + return $filename; + } + return FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $filename); + } } diff --git a/lib/Froxlor/Cron/Http/Lighttpd.php b/lib/Froxlor/Cron/Http/Lighttpd.php index 233236a0..968ab62c 100644 --- a/lib/Froxlor/Cron/Http/Lighttpd.php +++ b/lib/Froxlor/Cron/Http/Lighttpd.php @@ -336,24 +336,9 @@ class Lighttpd extends HttpConfigBase $_pos = strrpos($_tmp_path, '/'); $_inc_path = substr($_tmp_path, $_pos + 1); - // maindomain - if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) { - $vhost_no = '50'; - } elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) { - // sub-but-main-domain - $vhost_no = '51'; - } else { - // subdomains - // number of dots in a domain specifies it's position (and depth of subdomain) starting at 89 going downwards on higher depth - $vhost_no = (string)(90 - substr_count($domain['domain'], ".") + 1); - } - - if ($ssl == '1') { - $vhost_no = (int)$vhost_no += 10; - } - - $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf'); - $included_vhosts[] = $_inc_path . '/vhosts/' . $vhost_no . '_' . $domain['domain'] . '.conf'; + $filename = self::getVhostFilename($domain, ($ssl == '1'), true); + $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/vhosts/' . $filename); + $included_vhosts[] = $_inc_path . '/vhosts/' . $filename; } if (!isset($this->lighttpd_data[$vhost_filename])) { diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index 51230334..3d2ad85e 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -467,26 +467,6 @@ class Nginx extends HttpConfigBase } } - protected function getVhostFilename($domain, $ssl_vhost = false) - { - if ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && ((int)$domain['ismainbutsubto'] == 0 || Domain::domainMainToSubExists($domain['ismainbutsubto']) == false)) { - $vhost_no = '35'; - } elseif ((int)$domain['parentdomainid'] == 0 && Domain::isCustomerStdSubdomain((int)$domain['id']) == false && (int)$domain['ismainbutsubto'] > 0) { - $vhost_no = '30'; - } else { - // number of dots in a domain specifies it's position (and depth of subdomain) starting at 29 going downwards on higher depth - $vhost_no = (string)(30 - substr_count($domain['domain'], ".") + 1); - } - - if ($ssl_vhost === true) { - $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_ssl_vhost_' . $domain['domain'] . '.conf'); - } else { - $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/' . $vhost_no . '_froxlor_normal_vhost_' . $domain['domain'] . '.conf'); - } - - return $vhost_filename; - } - protected function getVhostContent($domain, $ssl_vhost = false) { if ($ssl_vhost === true && $domain['ssl'] != '1' && $domain['ssl_redirect'] != '1') { diff --git a/lib/Froxlor/Domain/Domain.php b/lib/Froxlor/Domain/Domain.php index 21aeead0..0f7a300b 100644 --- a/lib/Froxlor/Domain/Domain.php +++ b/lib/Froxlor/Domain/Domain.php @@ -235,51 +235,30 @@ class Domain } /** - * check whether a domain has subdomains added as full-domains - * #329 + * get ids of domains that are main domains but a subdomain of another main domain (for DNS) * - * @param int $id domain-id + * @param int $id main-domain to check * - * @return bool + * @return array * @throws \Exception */ - public static function domainHasMainSubDomains(int $id): bool + public static function getMainSubdomainIds(int $id): array { $result_stmt = Database::prepare(" - SELECT COUNT(`id`) as `mainsubs` FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE `ismainbutsubto` = :id"); - $result = Database::pexecute_first($result_stmt, [ - 'id' => $id - ]); - - if ($result && isset($result['mainsubs'])) { - return $result['mainsubs'] > 0; - } - return false; - } - - /** - * check whether a subof-domain exists - * #329 - * - * @param int $id subof-domain-id - * - * @return bool - * @throws \Exception - */ - public static function domainMainToSubExists(int $id): bool - { - $result_stmt = Database::prepare(" - SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `id` = :id"); + SELECT id + FROM `" . TABLE_PANEL_DOMAINS . "` + WHERE + isbinddomain = 1 AND + domain LIKE CONCAT('%.', ( SELECT d.domain FROM `" . TABLE_PANEL_DOMAINS . "` AS d WHERE d.id = :id )) + "); Database::pexecute($result_stmt, [ 'id' => $id ]); - $result = $result_stmt->fetch(PDO::FETCH_ASSOC); - - if ($result && isset($result['id'])) { - return $result['id'] > 0; + $result = []; + while ($entry = $result_stmt->fetch(PDO::FETCH_ASSOC)) { + $result = $entry['id']; } - return false; + return $result; } /** diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index c48d0ce3..5400cc7d 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -60,12 +60,6 @@ return [ 'type' => 'select', 'select_var' => $domains ], - 'issubof' => [ - 'label' => lng('domains.issubof'), - 'desc' => lng('domains.issubofinfo'), - 'type' => 'select', - 'select_var' => $subtodomains - ], 'caneditdomain' => [ 'label' => lng('admin.domain_editable.title'), 'desc' => lng('admin.domain_editable.desc'), diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index c8f81bea..b6a9c308 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -65,13 +65,6 @@ return [ 'select_var' => $domains, 'selected' => $result['aliasdomain'] ], - 'issubof' => [ - 'label' => lng('domains.issubof'), - 'desc' => lng('domains.issubofinfo'), - 'type' => 'select', - 'select_var' => $subtodomains, - 'selected' => $result['ismainbutsubto'] - ], 'associated_info' => [ 'label' => lng('domains.associated_with_domain'), 'type' => 'label', diff --git a/lng/de.lng.php b/lng/de.lng.php index 7ce6d207..b899a717 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -665,9 +665,6 @@ return [ 'aliasdomains' => 'Aliasdomains', 'redirectifpathisurl' => 'Redirect-Code (Standard: leer)', 'redirectifpathisurlinfo' => 'Der Redirect-Code kann gewählt werden, wenn der eingegebene Pfad eine URL ist.
HINWEIS: Änderungen werden nur wirksam wenn der Pfad eine URL ist.', - 'issubof' => 'Diese Domain ist eine Subdomain von der Domain', - 'issubofinfo' => 'Diese Einstellung muss gesetzt werden, wenn Sie eine Subdomain einer Hauptdomain als Hauptdomain anlegen (z. B. soll "www.domain.tld" hinzugefügt werden, somit muss hier "domain.tld" ausgewählt werden).', - 'nosubtomaindomain' => 'Keine Subdomain einer Hauptdomain', 'ipandport_multi' => [ 'title' => 'IP-Adresse(n)', 'description' => 'Definieren Sie eine oder mehrere IP-Adresse(n) für diese Domain.

Hinweis: Die IP-Adressen können nicht geändert werden, sollte die Domain als Alias-Domain für eine andere Domain konfiguriert worden sein.
', @@ -1287,7 +1284,6 @@ Vielen Dank, Ihr Administrator', 'admin_quotas_reallyenforce' => 'Sind Sie sicher, dass Sie allen Benutzern das Default-Quota zuweisen wollen? Dies kann nicht rückgängig gemacht werden!', 'phpsetting_reallydelete' => 'Wollen Sie diese PHP-Einstellungen wirklich löschen? Alle Domains die diese Einstellungen bis jetzt verwendet haben, werden dann auf die Standardeinstellungen umgestellt.', 'fpmsetting_reallydelete' => 'Wollen Sie diese PHP-FPM Einstellungen wirklich löschen? Alle PHP Konfigurationen die diese Einstellungen bis jetzt verwendet haben, werden dann auf die Standardeinstellungen umgestellt.', - 'remove_subbutmain_domains' => 'Auch Domains entfernen, welche als volle Domains hinzugefügt wurden, aber Subdomains von dieser Domain sind?', 'customer_reallyunlock' => 'Wollen Sie den Kunden "%s" wirklich entsperren?', 'admin_integritycheck_reallyfix' => 'Möchten Sie wirklich versuchen sämtliche Datenbank-Integritätsprobleme automatisch zu beheben?', 'plan_reallydelete' => 'Wollen Sie den Hostingplan %s wirklich löschen?', diff --git a/lng/en.lng.php b/lng/en.lng.php index 0a05daf4..d4cb30fa 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -731,9 +731,6 @@ return [ 'aliasdomains' => 'Alias domains', 'redirectifpathisurl' => 'Redirect code (default: empty)', 'redirectifpathisurlinfo' => 'You only need to select one of these if you entered an URL as path
NOTE: Changes are only applied if the given path is an URL.', - 'issubof' => 'This domain is a subdomain of another domain', - 'issubofinfo' => 'You have to set this to the correct domain if you want to add a subdomain as full-domain (e.g. you want to add "www.domain.tld", you have to select "domain.tld" here)', - 'nosubtomaindomain' => 'No subdomain of a full domain', 'ipandport_multi' => [ 'title' => 'IP address(es)', 'description' => 'Specify one or more IP address for the domain.

NOTE: IP addresses cannot be changed when the domain is configured as alias-domain of another domain.
', @@ -1399,7 +1396,6 @@ Yours sincerely, your administrator', 'admin_quotas_reallyenforce' => 'Do you really want to enforce the default quota to all Users? This cannot be reverted!', 'phpsetting_reallydelete' => 'Do you really want to delete these settings? All domains which use these settings currently will be changed to the default config.', 'fpmsetting_reallydelete' => 'Do you really want to delete these php-fpm settings? All php configurations which use these settings currently will be changed to the default config.', - 'remove_subbutmain_domains' => 'Also remove domains which are added as full domains but which are subdomains of this domain?', 'customer_reallyunlock' => 'Do you really want to unlock customer %s?', 'admin_integritycheck_reallyfix' => 'Do you really want to try fixing all database integrity problems automatically?', 'plan_reallydelete' => 'Do you really want to delete the hosting plan %s?', diff --git a/lng/es.lng.php b/lng/es.lng.php index 28eb7454..f5d5974d 100644 --- a/lng/es.lng.php +++ b/lng/es.lng.php @@ -731,9 +731,6 @@ return [ 'aliasdomains' => 'Alias dominios', 'redirectifpathisurl' => 'Código de redirección (por defecto: vacío)', 'redirectifpathisurlinfo' => 'Sólo tiene que seleccionar una de estas opciones si ha introducido una URL como ruta
NOTA: Los cambios sólo se aplican si la ruta indicada es una URL.', - 'issubof' => 'Este dominio es un subdominio de otro dominio', - 'issubofinfo' => 'Si desea añadir un subdominio como dominio completo, deberá establecerlo en el dominio correcto (por ejemplo, si desea añadir "www.domain.tld", deberá seleccionar "dominio.tld").', - 'nosubtomaindomain' => 'No es subdominio de un dominio completo', 'ipandport_multi' => [ 'title' => 'Direcciones IP', 'description' => 'Especifique una o más direcciones IP para el dominio.

NOTA: Las direcciones IP no pueden cambiarse cuando el dominio está configurado como alias-dominio de otro dominio.
' @@ -1390,7 +1387,6 @@ Atentamente, su administrador' 'admin_quotas_reallyenforce' => '¿Realmente desea aplicar la cuota por defecto a todos los usuarios? Esto no se puede revertir.', 'phpsetting_reallydelete' => '¿Realmente desea eliminar esta configuración? Todos los dominios que usen esta configuración serán cambiados a la configuración por defecto.', 'fpmsetting_reallydelete' => '¿Realmente desea eliminar esta configuración de php-fpm? Todas las configuraciones de php que utilicen estos ajustes se cambiarán a la configuración por defecto.', - 'remove_subbutmain_domains' => '¿Quitar también los dominios que se añaden como dominios completos pero que son subdominios de este dominio?', 'customer_reallyunlock' => '¿Realmente quieres desbloquear al cliente %s?', 'admin_integritycheck_reallyfix' => '¿Realmente quieres intentar arreglar todos los problemas de integridad de la base de datos automáticamente?', 'plan_reallydelete' => '¿De verdad quieres eliminar el plan de alojamiento %s?', diff --git a/lng/it.lng.php b/lng/it.lng.php index af5bff91..58610b82 100644 --- a/lng/it.lng.php +++ b/lng/it.lng.php @@ -732,9 +732,6 @@ return [ 'aliasdomains' => 'Alias domini', 'redirectifpathisurl' => 'Codice di redirezione (Predefinito: vuoto)', 'redirectifpathisurlinfo' => 'È necessario selezionare uno di questi se hai inserito un URL come percorso', - 'issubof' => 'Questo dominio è un sottodominio di un altro dominio', - 'issubofinfo' => 'Devi impostare correttamente questo dominio se si desidera aggiungere un sottodominio come dominio completo (es. si vuole aggiungere "www.domain.tld", devi selezionare qui "domain.tld")', - 'nosubtomaindomain' => 'No sottodominio di un dominio completo', 'ipandport_multi' => [ 'title' => 'Indirizzi IP', 'description' => 'Specifica uno o più indirizzi IP per il dominio.

NOTA: L\'indirizzo IP non può essere modificato quando il dominio è configurato come alias-domain di un altro dominio.
', @@ -1196,7 +1193,6 @@ Cordiali Saluti, Team Froxlor', 'admin_quotas_reallywipe' => 'Sei sicuro di voler cancellare tutti i limiti dalla tabella mail_users? Questa operazione non può essere annullata!', 'admin_quotas_reallyenforce' => 'Sei sicuro di voler impostare il limite predefinito a tutti gli utenti? Questa operazione non può essere annullata!', 'phpsetting_reallydelete' => 'Do you really want to delete these settings? All domains which use these settings currently will be changed to the default config.', - 'remove_subbutmain_domains' => 'Rimuover anche i domini che sono stati aggiunti come domini completi, ma quali sono i sottodomini di questo dominio?', 'customer_reallyunlock' => 'Sei sicuro di voler sbloccare il cliente %s?', 'admin_customer_alsoremovemail' => 'Eliminare completamente i dati della posta elettronica dal filesystem??', 'admin_customer_alsoremoveftphomedir' => 'Rimuovere anche la cartella homedir dell\'utente FTP?', diff --git a/lng/nl.lng.php b/lng/nl.lng.php index ad47606f..02548024 100644 --- a/lng/nl.lng.php +++ b/lng/nl.lng.php @@ -400,9 +400,6 @@ return [ 'aliasdomains' => 'Alternatieve domeinnamen', 'redirectifpathisurl' => 'Doorverwijzingscode (standaard: leegt)', 'redirectifpathisurlinfo' => 'U dient deze alleen op te geven indien u een URL als pad hebt opgegeven', - 'issubof' => 'Dit domein is een subdomein van een ander domein', - 'issubofinfo' => 'U dient het correcte domein op te geven indien u een subdomein als volledig domein wilt (bijvoorbeeld als u "www.domain.tld" wilt gebruiken, dan geeft u hier "domain.tld")', - 'nosubtomaindomain' => 'Geen subdomein van volledig domein', ], 'emails' => [ 'description' => 'Hier kunt u e-mail adressen maken en wijzigen.
Een account is net als een brievenbus voor uw huis. Als iemand u mail stuurt wordt dit op uw account bezorgd.

Om uw emails te downloaden moet u het volgende instellen in uw mailprogramma: (De schuingedrukte gegevens moeten gewijzigd worden in wat u ingegeven heeft!)
Servernaam: Domeinnaam
Gebruikersnaam: Account naam / E-mailadres
Wachtwoord: het door u ingegeven wachtwoord', @@ -741,7 +738,6 @@ Met vriendelijke groet, uw beheerder', 'admin_quotas_reallywipe' => 'Weet u zeker dat u alle quota wilt verwijderen? Dit is niet terug te draaien!', 'admin_quotas_reallyenforce' => 'Weet u zeker dat u quota wilt afdwingen? Dit is niet terug te draaien!', 'phpsetting_reallydelete' => 'Weet u zeker dat u deze instellingen wilt verwijderen? Alle domeinen die deze configuratie gebruiken zullen terugvallen op de standaardinstellingen.', - 'remove_subbutmain_domains' => 'Verwijder ook domeinen die als volledige domeinen zijn opgegeven maar een subdomein zijn van dit domein?', 'customer_reallyunlock' => 'Weet u zeker dat u klant %s? wilt ontgrendelen', ], 'serversettings' => [ From 2e6b939ec6d4ed90d8657a8915c87da845efd4e4 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 23 May 2023 15:21:25 +0200 Subject: [PATCH 02/26] set dbversion Signed-off-by: Michael Kaufmann --- install/froxlor.sql.php | 2 +- install/updates/froxlor/update_2.x.inc.php | 2 +- lib/Froxlor/Froxlor.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 8b680cfe..a4cb7c5a 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -744,7 +744,7 @@ opcache.validate_timestamps'), ('panel', 'logo_overridecustom', '0'), ('panel', 'settings_mode', '0'), ('panel', 'version', '2.0.19'), - ('panel', 'db_version', '202304260'); + ('panel', 'db_version', '202305230'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/updates/froxlor/update_2.x.inc.php b/install/updates/froxlor/update_2.x.inc.php index 5c035172..50f0f3cb 100644 --- a/install/updates/froxlor/update_2.x.inc.php +++ b/install/updates/froxlor/update_2.x.inc.php @@ -498,5 +498,5 @@ if (Froxlor::isDatabaseVersion('202304260')) { Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;"); Update::lastStepStatus(0); - Froxlor::updateToDbVersion('202305231'); + Froxlor::updateToDbVersion('202305230'); } diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 6f05abf1..df17100a 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -34,7 +34,7 @@ final class Froxlor const VERSION = '2.0.19'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202304260'; + const DBVERSION = '202305230'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; From 09b3c1c45a14be9e7394511118366b4908aaf363 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 24 May 2023 09:05:50 +0200 Subject: [PATCH 03/26] implement Domains.duplicate() API call, refs #807 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Domains.php | 134 ++++++++++++++++++++++++--- tests/Domains/DomainsTest.php | 20 ++++ 2 files changed, 142 insertions(+), 12 deletions(-) diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index ab81efd5..1b4bf6f2 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -110,7 +110,7 @@ class Domains extends ApiCommand implements ResourceEntity * * @param number $domain_id * @param bool $ssl_only - * optional, return only ssl enabled ip's, default false + * optional, return only ssl enabled ips, default false * @return array */ private function getIpsForDomain($domain_id = 0, $ssl_only = false) @@ -207,7 +207,7 @@ class Domains extends ApiCommand implements ResourceEntity * @param string $ssl_specialsettings * optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty * @param bool $include_specialsettings - * optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false + * optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false * @param bool $notryfiles * optional, [nginx only] do not generate the default try-files directive, default 0 (false) * @param bool $writeaccesslog @@ -216,7 +216,7 @@ class Domains extends ApiCommand implements ResourceEntity * optional, Enable writing an error-log file for this domain, default 1 (true) * @param string $documentroot * optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be - * aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also + * aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also * specifying a URL is possible here (redirect), default empty (autogenerated) * @param bool $phpenabled * optional, whether php is enabled for this domain, default 0 (false) @@ -241,7 +241,7 @@ class Domains extends ApiCommand implements ResourceEntity * optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport * parameter * @param bool $sslenabled - * optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default + * optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default * 1 (true) * @param bool $http2 * optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default @@ -249,9 +249,9 @@ class Domains extends ApiCommand implements ResourceEntity * @param int $hsts_maxage * optional max-age value for HSTS header * @param bool $hsts_sub - * optional whether or not to add subdomains to the HSTS header + * optional whether to add subdomains to the HSTS header * @param bool $hsts_preload - * optional whether or not to preload HSTS header value + * optional whether to preload HSTS header value * @param bool $ocsp_stapling * optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL * @param bool $honorcipherorder @@ -260,7 +260,7 @@ class Domains extends ApiCommand implements ResourceEntity * optional whether to enable or disable TLS sessiontickets (RFC 5077) for this domain. default 1 * (true), requires SSL * @param bool $override_tls - * optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable + * optional whether to override system-tls settings like protocol, ssl-ciphers and if applicable * tls-1.3 ciphers, requires change_serversettings flag for the admin, default false * @param array $ssl_protocols * optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required @@ -1076,7 +1076,7 @@ class Domains extends ApiCommand implements ResourceEntity * @param string $ssl_specialsettings * optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty * @param bool $include_specialsettings - * optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false + * optional, whether to include non-ssl specialsettings in the generated ssl-vhost, default false * @param bool $specialsettingsforsubdomains * optional, whether to apply specialsettings to all subdomains of this domain, default is read from * setting system.apply_specialsettings_default @@ -1088,7 +1088,7 @@ class Domains extends ApiCommand implements ResourceEntity * optional, Enable writing an error-log file for this domain, default 1 (true) * @param string $documentroot * optional, specify homedir of domain by specifying a directory (relative to customer-docroot), be - * aware, if path starts with / it it considered a full path, not relative to customer-docroot. Also + * aware, if path starts with / it is considered a full path, not relative to customer-docroot. Also * specifying a URL is possible here (redirect), default empty (autogenerated) * @param bool $phpenabled * optional, whether php is enabled for this domain, default 0 (false) @@ -1117,7 +1117,7 @@ class Domains extends ApiCommand implements ResourceEntity * optional, if set to true and no $ssl_ipandport value is given, the ip's get removed, otherwise, the * currently set value is used, default false * @param bool $sslenabled - * optional, whether or not SSL is enabled for this domain, regardless of the assigned ssl-ips, default + * optional, whether SSL is enabled for this domain, regardless of the assigned ssl-ips, default * 1 (true) * @param bool $http2 * optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default @@ -1125,9 +1125,9 @@ class Domains extends ApiCommand implements ResourceEntity * @param int $hsts_maxage * optional max-age value for HSTS header * @param bool $hsts_sub - * optional whether or not to add subdomains to the HSTS header + * optional whether to add subdomains to the HSTS header * @param bool $hsts_preload - * optional whether or not to preload HSTS header value + * optional whether to preload HSTS header value * @param bool $ocsp_stapling * optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL * @param bool $honorcipherorder @@ -2187,4 +2187,114 @@ class Domains extends ApiCommand implements ResourceEntity } throw new Exception("Not allowed to execute given command.", 403); } + + /** + * duplicate domain entry by either id or domainname. All parameters from Domains.add() can be used + * to overwrite source entity values if necessary. + * + * @param int $id + * optional, the domain-id + * @param string $domainname + * optional, the domainname + * @param string $domain + * required, name of the new domain to be added + * + * @access admin + * @return string json-encoded array + * @throws Exception + */ + public function duplicate() + { + if ($this->isAdmin()) { + // parameters + $id = $this->getParam('id', true, 0); + $dn_optional = $id > 0; + $domainname = $this->getParam('domainname', $dn_optional, ''); + $p_domain = $this->getParam('domain'); + + // get requested domain + $result = $this->apiCall('Domains.get', [ + 'id' => $id, + 'domainname' => $domainname, + ]); + + // clear some defaults + unset($result['domain_ace']); + unset($result['adminid']); + unset($result['documentroot']); + unset($result['registration_date']); + unset($result['termination_date']); + unset($result['zonefile']); + // clear auto-generated values + unset($result['bindserial']); + unset($result['dkim_privkey']); + unset($result['dkim_pubkey']); + // clear api-call generated fields + unset($result['domain_hascert']); + + // set correct ip/port information + $domain_ips = $result['ipsandports']; + unset($result['ipsandports']); + $result['ipandport'] = []; + $result['ssl_ipandport'] = []; + foreach ($domain_ips as $dip) { + if ($dip['ssl'] == 1) { + $result['ssl_ipandport'][] = $dip['id']; + } else { + $result['ipandport'][] = $dip['id']; + } + } + + // check whether we are changing the customer/owner + if ($this->getParam('customerid', true, 0) == 0 && $this->getParam('loginname', true, '') == '') { + $customerid = $result['customerid']; + } else { + $customer = $this->getCustomerData(); + $customerid = $customer['customerid']; + } + + // check for alias-domain and whether it belongs to the target user + if (!empty($result['aliasdomain']) && $customerid == $result['customerid']) { + // duplicate alias entry + $result['alias'] = $result['aliasdomain']; + } + unset($result['aliasdomain']); + + // validate possible fpm configs and whether the customer is allowed to use them + if ($customerid != $result['customerid']) { + $allowed_phpconfigs = json_decode($customer['allowed_phpconfigs'] ?? '[]', true); + if (empty($allowed_phpconfigs)) { + // system defaults + unset($result['phpsettingid']); + } elseif (!in_array($result['phpsettingid'], $allowed_phpconfigs)) { + // use the first customer allowed config + $result['phpsettingid'] = array_shift($allowed_phpconfigs); + } + } + + // translate serveralias values + $result['selectserveralias'] = 2; + if ((int)$result['wwwserveralias'] == 1) { + $result['selectserveralias'] = 1; + } elseif ((int)$result['iswildcarddomain'] == 1) { + $result['selectserveralias'] = 0; + } + unset($result['wwwserveralias']); + unset($result['iswildcarddomain']); + + $additional_params = $this->getParamList(); + // unset unneeded params from this call + unset($additional_params['id']); + unset($additional_params['domainname']); + unset($additional_params['domain']); + + // set new values and merge with optional add() parameters + $new_domain = array_merge($result, $additional_params); + $new_domain['domain'] = $p_domain; + + $result_new = $this->apiCall('Domains.add', $new_domain); + return $this->response($result_new); + } + throw new Exception("Not allowed to execute given command.", 403); + } } diff --git a/tests/Domains/DomainsTest.php b/tests/Domains/DomainsTest.php index 716f18e6..48a771f2 100644 --- a/tests/Domains/DomainsTest.php +++ b/tests/Domains/DomainsTest.php @@ -385,6 +385,26 @@ class DomainsTest extends TestCase * * @depends testAdminDomainsMove */ + public function testAdminDomainsDuplicate() + { + global $admin_userdata; + $data = [ + 'domainname' => 'test.local', + 'domain' => 'test.duplicate.local', + 'description' => 'duplicated domain' + ]; + $json_result = Domains::getLocal($admin_userdata, $data)->duplicate(); + $result = json_decode($json_result, true)['data']; + $this->assertEquals('/var/customers/webs/test3/test.duplicate.local/', $result['documentroot']); + $this->assertEquals(1, $result['email_only']); + $this->assertEquals('test.duplicate.local', $result['domain']); + $this->assertEquals('duplicated domain', $result['description']); + } + + /** + * + * @depends testAdminDomainsDuplicate + */ public function testAdminDomainsDelete() { global $admin_userdata; From 233bf27afed66a34675c180301879beaa5870c8f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 24 May 2023 16:02:07 +0200 Subject: [PATCH 04/26] add Froxlor.generateLoginLink() API call to allow generation of one-time-login links for customers, thx to INWX for supporting and sponsoring this feature Signed-off-by: Michael Kaufmann --- index.php | 55 +++++++++++++++- install/froxlor.sql.php | 11 +++- install/updates/froxlor/update_2.x.inc.php | 14 +++- lib/Froxlor/Api/Commands/Froxlor.php | 74 ++++++++++++++++++++++ lib/Froxlor/Api/FroxlorRPC.php | 4 +- lib/Froxlor/Cli/MasterCron.php | 3 + lib/Froxlor/Froxlor.php | 2 +- lib/tables.inc.php | 1 + lng/de.lng.php | 1 + lng/en.lng.php | 1 + 10 files changed, 160 insertions(+), 6 deletions(-) diff --git a/index.php b/index.php index d59146e3..de0b38f4 100644 --- a/index.php +++ b/index.php @@ -26,6 +26,7 @@ const AREA = 'login'; require __DIR__ . '/lib/init.php'; +use Froxlor\Api\FroxlorRPC; use Froxlor\CurrentUser; use Froxlor\Customer\Customer; use Froxlor\Database\Database; @@ -37,10 +38,10 @@ use Froxlor\PhpHelper; use Froxlor\Settings; use Froxlor\System\Crypt; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\User; use Froxlor\Validate\Validate; -use Froxlor\Language; if ($action == '') { $action = 'login'; @@ -730,6 +731,58 @@ if ($action == 'resetpwd') { } } +// one-time link login +if ($action == 'll') { + if (!Froxlor::hasUpdates() && !Froxlor::hasDbUpdates()) { + $loginname = Request::get('ln'); + $hash = Request::get('h'); + if ($loginname && $hash) { + $sel_stmt = Database::prepare(" + SELECT * FROM `" . TABLE_PANEL_LOGINLINKS . "` + WHERE `loginname` = :loginname AND `hash` = :hash + "); + try { + $entry = Database::pexecute_first($sel_stmt, ['loginname' => $loginname, 'hash' => $hash]); + } catch (Exception $e) { + $entry = false; + } + if ($entry) { + // delete entry + $del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `loginname` = :loginname AND `hash` = :hash"); + Database::pexecute($del_stmt, ['loginname' => $loginname, 'hash' => $hash]); + if (time() <= $entry['valid_until']) { + $valid = true; + // validate source ip if specified + if (!empty($entry['allowed_from'])) { + $valid = false; + $ip_list = explode(",", $entry['allowed_from']); + if (FroxlorRPC::validateAllowedFrom($ip_list, $_SERVER['REMOTE_ADDR'])) { + $valid = true; + } + } + if ($valid) { + // login user / select only non-deactivated (in case the user got deactivated after generating the link) + $userinfo_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `loginname`= :loginname AND `deactivated` = 0"); + try { + $userinfo = Database::pexecute_first($userinfo_stmt, [ + "loginname" => $loginname + ]); + } catch (Exception $e) { + $userinfo = false; + } + if ($userinfo) { + $userinfo['userid'] = $userinfo['customerid']; + $userinfo['adminsession'] = 0; + finishLogin($userinfo); + } + } + } + } + } + } + Response::redirectTo('index.php'); +} + function finishLogin($userinfo) { if (isset($userinfo['userid']) && $userinfo['userid'] != '') { diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index a4cb7c5a..57901d03 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -744,7 +744,7 @@ opcache.validate_timestamps'), ('panel', 'logo_overridecustom', '0'), ('panel', 'settings_mode', '0'), ('panel', 'version', '2.0.19'), - ('panel', 'db_version', '202305230'); + ('panel', 'db_version', '202305240'); DROP TABLE IF EXISTS `panel_tasks`; @@ -1051,4 +1051,13 @@ CREATE TABLE `panel_usercolumns` ( KEY adminid (adminid), KEY customerid (customerid) ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; + +DROP TABLE IF EXISTS `panel_loginlinks`; +CREATE TABLE `panel_loginlinks` ( + `hash` varchar(500) NOT NULL, + `loginname` varchar(50) NOT NULL, + `valid_until` int(15) NOT NULL, + `allowed_from` text NOT NULL, + UNIQUE KEY `loginname` (`loginname`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; FROXLORSQL; diff --git a/install/updates/froxlor/update_2.x.inc.php b/install/updates/froxlor/update_2.x.inc.php index 50f0f3cb..30eafde4 100644 --- a/install/updates/froxlor/update_2.x.inc.php +++ b/install/updates/froxlor/update_2.x.inc.php @@ -498,5 +498,17 @@ if (Froxlor::isDatabaseVersion('202304260')) { Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;"); Update::lastStepStatus(0); - Froxlor::updateToDbVersion('202305230'); + Update::showUpdateStep("Creating new tables and fields"); + Database::query("DROP TABLE IF EXISTS `panel_loginlinks`;"); + $sql = "CREATE TABLE `panel_loginlinks` ( + `hash` varchar(500) NOT NULL, + `loginname` varchar(50) NOT NULL, + `valid_until` int(15) NOT NULL, + `allowed_from` text NOT NULL, + UNIQUE KEY `loginname` (`loginname`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; + Database::query($sql); + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202305240'); } diff --git a/lib/Froxlor/Api/Commands/Froxlor.php b/lib/Froxlor/Api/Commands/Froxlor.php index 690b5880..d7cb4920 100644 --- a/lib/Froxlor/Api/Commands/Froxlor.php +++ b/lib/Froxlor/Api/Commands/Froxlor.php @@ -37,6 +37,7 @@ use Froxlor\Settings; use Froxlor\SImExporter; use Froxlor\System\Cronjob; use Froxlor\System\Crypt; +use Froxlor\Validate\Validate; use PDO; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; @@ -269,6 +270,79 @@ class Froxlor extends ApiCommand return $this->response(Crypt::generatePassword($length)); } + /** + * return a one-time login link URL for a given user + * + * @param int $customerid optional, required if $loginname is not specified, user to create link for + * @param string $loginname optional, required if $customerid is not specified, user to create link for + * @param int $valid_time optional, value in seconds how long the link will be valid, default is 10 seconds, valid values are numbers from 10 to 120 + * @param string $allowed_from optional, comma separated list of ip addresses or networks to allow login from via this link + * + * @access admin + * @return string json-encoded array [base => domain, uri => relative link] + * @throws Exception + */ + public function generateLoginLink() + { + if ($this->isAdmin()) { + $customer = $this->getCustomerData(); + + // cannot create link for deactivated users + if ((int)$customer['deactivated'] == 1) { + throw new Exception("Cannot generate link for deactivated user", 406); + } + + $valid_time = (int)$this->getParam('valid_time', true, 10); + $allowed_from = $this->getParam('allowed_from', true, ''); + + $valid_time = Validate::validate($valid_time, 'valid time', '/^(1[0-1][0-9]|120|[1-9][0-9])$/', 'invalid_validtime', [10], true); + + // validate allowed_from + if (!empty($allowed_from)) { + $ip_list = array_map('trim', explode(",", $allowed_from)); + $_check_list = $ip_list; + foreach ($_check_list as $idx => $ip) { + if (Validate::validate_ip2($ip, true, 'invalidip', true, true, true) == false) { + throw new Exception('Invalid ip address', 406); + } + // check for cidr + if (strpos($ip, '/') !== false) { + $ipparts = explode("/", $ip); + // shorten IP + $ip = inet_ntop(inet_pton($ipparts[0])); + // re-add cidr + $ip .= '/' . $ipparts[1]; + } else { + // shorten IP + $ip = inet_ntop(inet_pton($ip)); + } + $ip_list[$idx] = $ip; + } + $allowed_from = implode(",", array_unique($ip_list)); + } + + $hash = hash('sha256', openssl_random_pseudo_bytes(64 * 64)); + + $ins_stmt = Database::prepare(" + INSERT INTO `" . TABLE_PANEL_LOGINLINKS . "` + SET `hash` = :hash, `loginname` = :loginname, `valid_until` = :validuntil, `allowed_from` = :allowedfrom + ON DUPLICATE KEY UPDATE `hash` = :hash, `valid_until` = :validuntil, `allowed_from` = :allowedfrom + "); + Database::pexecute($ins_stmt, [ + 'hash' => $hash, + 'loginname' => $customer['loginname'], + 'validuntil' => time() + $valid_time, + 'allowedfrom' => $allowed_from + ]); + + return $this->response([ + 'base' => 'https://' . Settings::Get('system.hostname') . '/' . (Settings::Get('system.froxlordirectlyviahostname') != 1 ? basename(\Froxlor\Froxlor::getInstallDir()) . '/' : ''), + 'uri' => 'index.php?action=ll&ln=' . $customer['loginname'] . '&h=' . $hash + ]); + } + throw new Exception("Not allowed to execute given command.", 403); + } + /** * can be used to remotely run the integritiy checks froxlor implements * diff --git a/lib/Froxlor/Api/FroxlorRPC.php b/lib/Froxlor/Api/FroxlorRPC.php index 4a85872b..ed5398dd 100644 --- a/lib/Froxlor/Api/FroxlorRPC.php +++ b/lib/Froxlor/Api/FroxlorRPC.php @@ -112,11 +112,11 @@ class FroxlorRPC * * @return bool */ - private static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool + public static function validateAllowedFrom(array $allowed_from, string $remote_addr): bool { // shorten IP for comparison $remote_addr = inet_ntop(inet_pton($remote_addr)); - // check for diret matches + // check for direct matches if (in_array($remote_addr, $allowed_from)) { return true; } diff --git a/lib/Froxlor/Cli/MasterCron.php b/lib/Froxlor/Cli/MasterCron.php index 72d43f70..ec85d230 100644 --- a/lib/Froxlor/Cli/MasterCron.php +++ b/lib/Froxlor/Cli/MasterCron.php @@ -166,6 +166,9 @@ final class MasterCron extends CliCommand FroxlorLogger::getInstanceOf()->setCronLog(0); } + // clean up possible old login-links + Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()"); + return $result; } diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index df17100a..39f4aab5 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -34,7 +34,7 @@ final class Froxlor const VERSION = '2.0.19'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202305230'; + const DBVERSION = '202305240'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/tables.inc.php b/lib/tables.inc.php index 43c52b08..26214333 100644 --- a/lib/tables.inc.php +++ b/lib/tables.inc.php @@ -56,3 +56,4 @@ const TABLE_PANEL_FPMDAEMONS = 'panel_fpmdaemons'; const TABLE_PANEL_PLANS = 'panel_plans'; const TABLE_API_KEYS = 'api_keys'; const TABLE_PANEL_USERCOLUMNS = 'panel_usercolumns'; +const TABLE_PANEL_LOGINLINKS = 'panel_loginlinks'; diff --git a/lng/de.lng.php b/lng/de.lng.php index b899a717..6cf9fcf9 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -926,6 +926,7 @@ return [ '2fa_wrongcode' => 'Der angegebene Code ist nicht korrekt', 'gnupgextensionnotavailable' => 'Die PHP GnuPG Extension ist nicht verfügbar. PGP Schlüssel können nicht validiert werden.', 'invalidpgppublickey' => 'Der angegebene PGP Public Key ist ungültig', + 'invalid_validtime' => 'Wert der valid_time in Sekunden muss zwischen 10 und 120 liegen.', ], 'extras' => [ 'description' => 'Hier können Sie zusätzliche Extras einrichten, wie zum Beispiel einen Verzeichnisschutz.
Die Änderungen sind erst nach einer kurzen Zeit wirksam.', diff --git a/lng/en.lng.php b/lng/en.lng.php index d4cb30fa..9169ec37 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -995,6 +995,7 @@ return [ '2fa_wrongcode' => 'The code entered is not valid', 'gnupgextensionnotavailable' => 'The PHP GnuPG extension is not available. Unable to validate PGP Public Key', 'invalidpgppublickey' => 'The PGP Public Key is not valid', + 'invalid_validtime' => 'Valid time in seconds can only be between 10 and 120', ], 'extras' => [ 'description' => 'Here you can add some extras, for example directory protection.
The system will need some time to apply the new settings after every change.', From 51b6e067e8c39b6af9c9d2fea80cd0aec2063d79 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 25 May 2023 08:26:39 +0200 Subject: [PATCH 05/26] idna encode umlaut-emailaddresses when adding/editing email-account; use correct password-suggestion-layout in change-email-account formfield Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/EmailAccounts.php | 10 ++++++++++ .../formfield.emails_accountchangepasswd.php | 17 ++++++++++------- .../email/formfield.emails_addaccount.php | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index f341c880..feb0cd9a 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -99,6 +99,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity Response::standardError('notallowedtouseaccounts', '', true); } + if (!empty($emailaddr)) { + $idna_convert = new IdnaWrapper(); + $emailaddr = $idna_convert->encode($emailaddr); + } + // get email address $result = $this->apiCall('Emails.get', [ 'id' => $id, @@ -357,6 +362,11 @@ class EmailAccounts extends ApiCommand implements ResourceEntity $ea_optional = $id > 0; $emailaddr = $this->getParam('emailaddr', $ea_optional, ''); + if (!empty($emailaddr)) { + $idna_convert = new IdnaWrapper(); + $emailaddr = $idna_convert->encode($emailaddr); + } + // validation $result = $this->apiCall('Emails.get', [ 'id' => $id, diff --git a/lib/formfields/customer/email/formfield.emails_accountchangepasswd.php b/lib/formfields/customer/email/formfield.emails_accountchangepasswd.php index 02cd8f5f..f18d69b7 100644 --- a/lib/formfields/customer/email/formfield.emails_accountchangepasswd.php +++ b/lib/formfields/customer/email/formfield.emails_accountchangepasswd.php @@ -43,13 +43,16 @@ return [ 'email_password' => [ 'label' => lng('login.password'), 'type' => 'password', - 'autocomplete' => 'off' - ], - 'email_password_suggestion' => [ - 'label' => lng('customer.generated_pwd'), - 'type' => 'text', - 'visible' => (Settings::Get('panel.password_regex') == ''), - 'value' => Crypt::generatePassword() + 'autocomplete' => 'off', + 'next_to' => [ + 'email_password_suggestion' => [ + 'next_to_prefix' => lng('customer.generated_pwd') . ':', + 'type' => 'text', + 'visible' => (Settings::Get('panel.password_regex') == ''), + 'value' => Crypt::generatePassword(), + 'readonly' => true + ] + ] ] ] ] diff --git a/lib/formfields/customer/email/formfield.emails_addaccount.php b/lib/formfields/customer/email/formfield.emails_addaccount.php index 01c871dd..ea0be6d6 100644 --- a/lib/formfields/customer/email/formfield.emails_addaccount.php +++ b/lib/formfields/customer/email/formfield.emails_addaccount.php @@ -46,7 +46,7 @@ return [ 'autocomplete' => 'off', 'mandatory' => true, 'next_to' => [ - 'admin_password_suggestion' => [ + 'email_password_suggestion' => [ 'next_to_prefix' => lng('customer.generated_pwd') . ':', 'type' => 'text', 'visible' => (Settings::Get('panel.password_regex') == ''), From da810ea95393dfaec68a70e30b7c887c50563a7e Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 25 May 2023 09:51:55 +0200 Subject: [PATCH 06/26] secure filename of local-archive in webupdate Signed-off-by: Michael Kaufmann --- admin_autoupdate.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/admin_autoupdate.php b/admin_autoupdate.php index c06331f1..dcaedae8 100644 --- a/admin_autoupdate.php +++ b/admin_autoupdate.php @@ -28,7 +28,7 @@ require __DIR__ . '/lib/init.php'; use Froxlor\Froxlor; use Froxlor\FroxlorLogger; -use Froxlor\Http\HttpClient; +use Froxlor\FileDir; use Froxlor\Install\AutoUpdate; use Froxlor\Settings; use Froxlor\UI\Panel\UI; @@ -132,7 +132,7 @@ elseif ($page == 'getdownload') { elseif ($page == 'extract') { if (isset($_POST['send']) && $_POST['send'] == 'send') { $toExtract = isset($_POST['archive']) ? $_POST['archive'] : null; - $localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract; + $localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir()); $result = AutoUpdate::extractZip($localArchive); if ($result > 0) { @@ -146,7 +146,7 @@ elseif ($page == 'extract') { Response::redirectTo('admin_updates.php'); } else { $toExtract = isset($_GET['archive']) ? $_GET['archive'] : null; - $localArchive = Froxlor::getInstallDir() . '/updates/' . $toExtract; + $localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract); } if (!file_exists($localArchive)) { From 8deaf6a0139309f25fc1e6ef6ab7eb37662b083f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 25 May 2023 12:33:43 +0200 Subject: [PATCH 07/26] frontend implementation of Domains.duplicate() Signed-off-by: Michael Kaufmann --- admin_domains.php | 17 ++++++++ lib/Froxlor/UI/Callbacks/Text.php | 43 +++++++++++++++++++ .../admin/tablelisting.domains.php | 5 +++ lng/de.lng.php | 2 + lng/en.lng.php | 2 + templates/Froxlor/user/inline-form.html.twig | 2 +- 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/admin_domains.php b/admin_domains.php index c295387c..408e64bc 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -636,6 +636,23 @@ if ($page == 'domains' || $page == 'overview') { 'alert_msg' => lng('domains.import_description') ]); } + } elseif ($action == 'duplicate') { + if (isset($_POST['send']) && $_POST['send'] == 'send') { + try { + Domains::getLocal($userinfo, $_POST)->duplicate(); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + Response::redirectTo($filename, [ + 'page' => $page, + 'searchfield' => 'd.domain_ace', + 'searchtext' => $_POST['domain'] ?? "" + ]); + } else { + Response::redirectTo($filename, [ + 'page' => 'overview' + ]); + } } } elseif ($page == 'domainssleditor') { require_once __DIR__ . '/ssl_editor.php'; diff --git a/lib/Froxlor/UI/Callbacks/Text.php b/lib/Froxlor/UI/Callbacks/Text.php index 3edfb72e..2ec9735e 100644 --- a/lib/Froxlor/UI/Callbacks/Text.php +++ b/lib/Froxlor/UI/Callbacks/Text.php @@ -25,10 +25,13 @@ namespace Froxlor\UI\Callbacks; +use Froxlor\CurrentUser; +use Froxlor\Database\Database; use Froxlor\Froxlor; use Froxlor\PhpHelper; use Froxlor\UI\Panel\UI; use Froxlor\User; +use PDO; class Text { @@ -105,4 +108,44 @@ class Text 'body' => $body ]; } + + public static function domainDuplicateModal(array $attributes): array + { + $linker = UI::getLinker(); + $result = $attributes['fields']; + + $customers = [ + 0 => lng('panel.please_choose') + ]; + $result_customers_stmt = Database::prepare(" + SELECT `customerid`, `loginname`, `name`, `firstname`, `company` + FROM `" . TABLE_PANEL_CUSTOMERS . "` " . (CurrentUser::getField('customers_see_all') ? '' : " WHERE `adminid` = :adminid ") . " + ORDER BY COALESCE(NULLIF(`name`,''), `company`) ASC + "); + $params = []; + if (CurrentUser::getField('customers_see_all') == '0') { + $params['adminid'] = CurrentUser::getField('adminid'); + } + Database::pexecute($result_customers_stmt, $params); + + while ($row_customer = $result_customers_stmt->fetch(PDO::FETCH_ASSOC)) { + $customers[$row_customer['customerid']] = User::getCorrectFullUserDetails($row_customer) . ' (' . $row_customer['loginname'] . ')'; + } + + $domdup_data = include Froxlor::getInstallDir() . '/lib/formfields/admin/domains/formfield.domains_duplicate.php'; + + $body = UI::twig()->render(UI::validateThemeTemplate('/user/inline-form.html.twig'), [ + 'formaction' => $linker->getLink(['section' => 'domains', 'page' => 'domains', 'action' => 'duplicate']), + 'formdata' => $domdup_data['domain_duplicate'], + 'editid' => $attributes['fields']['id'], + 'nosubmit' => 0 + ]); + return [ + 'entry' => $attributes['fields']['id'], + 'id' => 'ddModal' . $attributes['fields']['id'], + 'title' => lng('admin.domain_duplicate_named', [$attributes['fields']['domain']]), + 'action' => 'duplicate', + 'body' => $body + ]; + } } diff --git a/lib/tablelisting/admin/tablelisting.domains.php b/lib/tablelisting/admin/tablelisting.domains.php index 11f8ec5e..17aa75bc 100644 --- a/lib/tablelisting/admin/tablelisting.domains.php +++ b/lib/tablelisting/admin/tablelisting.domains.php @@ -161,6 +161,11 @@ return [ 'id' => ':id' ], ], + 'duplicate' => [ + 'icon' => 'fa-solid fa-clone', + 'title' => lng('admin.domain_duplicate'), + 'modal' => [Text::class, 'domainDuplicateModal'], + ], 'logfiles' => [ 'icon' => 'fa-solid fa-file', 'title' => lng('panel.viewlogs'), diff --git a/lng/de.lng.php b/lng/de.lng.php index b899a717..e6c25761 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -489,6 +489,8 @@ return [ 'adminguide' => 'Admin Guide', 'userguide' => 'User Guide', 'apiguide' => 'API Guide', + 'domain_duplicate' => 'Domain duplizieren', + 'domain_duplicate_named' => '%s duplizieren', ], 'apikeys' => [ 'no_api_keys' => 'Keine API Keys gefunden', diff --git a/lng/en.lng.php b/lng/en.lng.php index d4cb30fa..97f60ce4 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -500,6 +500,8 @@ return [ 'adminguide' => 'Admin guide', 'userguide' => 'User guide', 'apiguide' => 'API guide', + 'domain_duplicate' => 'Duplicate domain', + 'domain_duplicate_named' => 'Duplicate %s', ], 'apcuinfo' => [ 'clearcache' => 'Clear APCu cache', diff --git a/templates/Froxlor/user/inline-form.html.twig b/templates/Froxlor/user/inline-form.html.twig index 0df2fc4d..7c92faa1 100644 --- a/templates/Froxlor/user/inline-form.html.twig +++ b/templates/Froxlor/user/inline-form.html.twig @@ -1,2 +1,2 @@ {% import "Froxlor/form/form.html.twig" as form %} -{{ form.form(formdata, formaction|default('#'), formdata.title, editid|default(''), true, idprefix|default('')) }} +{{ form.form(formdata, formaction|default('#'), formdata.title, editid|default(''), nosubmit|default(true), idprefix|default('')) }} From 84599011cf2f3836c570eb904b889e0aaf95b701 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 26 May 2023 12:53:27 +0200 Subject: [PATCH 08/26] Allow editing/viewing of standard subdomain for customer, fixes #1121 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/SubDomains.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index 433871f0..3f95a2a1 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -865,7 +865,7 @@ class SubDomains extends ApiCommand implements ResourceEntity } /** - * lists all subdomain entries + * lists all customer domain/subdomain entries * * @param bool $with_ips * optional, default true @@ -910,17 +910,12 @@ class SubDomains extends ApiCommand implements ResourceEntity $custom_list_result = $_custom_list_result['list']; } $customer_ids = []; - $customer_stdsubs = []; foreach ($custom_list_result as $customer) { $customer_ids[] = $customer['customerid']; - $customer_stdsubs[$customer['customerid']] = $customer['standardsubdomain']; } if (empty($customer_ids)) { throw new Exception("Required resource unsatisfied.", 405); } - if (empty($customer_stdsubs)) { - throw new Exception("Required resource unsatisfied.", 405); - } $select_fields = [ '`d`.*' @@ -932,9 +927,6 @@ class SubDomains extends ApiCommand implements ResourceEntity $customer_ids = [ $this->getUserDetail('customerid') ]; - $customer_stdsubs = [ - $this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain') - ]; $select_fields = [ '`d`.`id`', @@ -963,7 +955,7 @@ class SubDomains extends ApiCommand implements ResourceEntity LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid` WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") AND `d`.`email_only` = '0' - AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit()); + " . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit()); $result = []; Database::pexecute($domains_stmt, $query_fields, true, true); From 426f20447325a729e0ce897d8ecc8e6532358f1e Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 26 May 2023 13:15:01 +0200 Subject: [PATCH 09/26] specify default search-field for on-page listing-search/filter Signed-off-by: Michael Kaufmann --- lib/Froxlor/UI/Listing.php | 1 + lib/tablelisting/admin/tablelisting.admins.php | 1 + lib/tablelisting/admin/tablelisting.domains.php | 1 + lib/tablelisting/admin/tablelisting.fpmconfigs.php | 1 + lib/tablelisting/admin/tablelisting.ipsandports.php | 1 + lib/tablelisting/admin/tablelisting.mysqlserver.php | 1 + lib/tablelisting/admin/tablelisting.phpconfigs.php | 1 + lib/tablelisting/admin/tablelisting.plans.php | 1 + templates/Froxlor/table/table.html.twig | 2 +- 9 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Froxlor/UI/Listing.php b/lib/Froxlor/UI/Listing.php index 3d3be00a..c32f30f4 100644 --- a/lib/Froxlor/UI/Listing.php +++ b/lib/Froxlor/UI/Listing.php @@ -230,6 +230,7 @@ class Listing 'label' => $coldata['label'], 'checked' => in_array($column, $tabellisting['visible_columns']), 'searchable' => $coldata['searchable'] ?? true, + 'isdefaultsearchfield' => $coldata['isdefaultsearchfield'] ?? false, ]; } } diff --git a/lib/tablelisting/admin/tablelisting.admins.php b/lib/tablelisting/admin/tablelisting.admins.php index aaa82126..d9abf86d 100644 --- a/lib/tablelisting/admin/tablelisting.admins.php +++ b/lib/tablelisting/admin/tablelisting.admins.php @@ -48,6 +48,7 @@ return [ 'field' => 'loginname', 'callback' => [Impersonate::class, 'admin'], 'sortable' => true, + 'isdefaultsearchfield' => true, ], 'name' => [ 'label' => lng('customer.name'), diff --git a/lib/tablelisting/admin/tablelisting.domains.php b/lib/tablelisting/admin/tablelisting.domains.php index 17aa75bc..3c484e11 100644 --- a/lib/tablelisting/admin/tablelisting.domains.php +++ b/lib/tablelisting/admin/tablelisting.domains.php @@ -48,6 +48,7 @@ return [ 'd.domain_ace' => [ 'label' => lng('domains.domainname'), 'field' => 'domain_ace', + 'isdefaultsearchfield' => true, ], 'ipsandports' => [ 'label' => lng('admin.ipsandports.ipsandports'), diff --git a/lib/tablelisting/admin/tablelisting.fpmconfigs.php b/lib/tablelisting/admin/tablelisting.fpmconfigs.php index bae9c366..2d2ac0bc 100644 --- a/lib/tablelisting/admin/tablelisting.fpmconfigs.php +++ b/lib/tablelisting/admin/tablelisting.fpmconfigs.php @@ -41,6 +41,7 @@ return [ 'description' => [ 'label' => lng('admin.phpsettings.description'), 'field' => 'description', + 'isdefaultsearchfield' => true, ], 'configs' => [ 'label' => lng('admin.phpsettings.activephpconfigs'), diff --git a/lib/tablelisting/admin/tablelisting.ipsandports.php b/lib/tablelisting/admin/tablelisting.ipsandports.php index 47046c48..b5f920fd 100644 --- a/lib/tablelisting/admin/tablelisting.ipsandports.php +++ b/lib/tablelisting/admin/tablelisting.ipsandports.php @@ -37,6 +37,7 @@ return [ 'ip' => [ 'label' => lng('admin.ipsandports.ip'), 'field' => 'ip', + 'isdefaultsearchfield' => true, ], 'port' => [ 'label' => lng('admin.ipsandports.port'), diff --git a/lib/tablelisting/admin/tablelisting.mysqlserver.php b/lib/tablelisting/admin/tablelisting.mysqlserver.php index 53877395..01efcf40 100644 --- a/lib/tablelisting/admin/tablelisting.mysqlserver.php +++ b/lib/tablelisting/admin/tablelisting.mysqlserver.php @@ -40,6 +40,7 @@ return [ 'caption' => [ 'label' => lng('admin.mysqlserver.caption'), 'field' => 'caption', + 'isdefaultsearchfield' => true, ], 'host' => [ 'label' => lng('admin.mysqlserver.host'), diff --git a/lib/tablelisting/admin/tablelisting.phpconfigs.php b/lib/tablelisting/admin/tablelisting.phpconfigs.php index 207f90b4..a2f025b1 100644 --- a/lib/tablelisting/admin/tablelisting.phpconfigs.php +++ b/lib/tablelisting/admin/tablelisting.phpconfigs.php @@ -42,6 +42,7 @@ return [ 'c.description' => [ 'label' => lng('admin.phpsettings.description'), 'field' => 'description', + 'isdefaultsearchfield' => true, ], 'domains' => [ 'label' => lng('admin.phpsettings.activedomains'), diff --git a/lib/tablelisting/admin/tablelisting.plans.php b/lib/tablelisting/admin/tablelisting.plans.php index a4e08ed2..be4dd5ff 100644 --- a/lib/tablelisting/admin/tablelisting.plans.php +++ b/lib/tablelisting/admin/tablelisting.plans.php @@ -40,6 +40,7 @@ return [ 'p.name' => [ 'label' => lng('admin.plans.name'), 'field' => 'name', + 'isdefaultsearchfield' => true, ], 'p.description' => [ 'label' => lng('admin.plans.description'), diff --git a/templates/Froxlor/table/table.html.twig b/templates/Froxlor/table/table.html.twig index 939b9b00..32d9dcb7 100644 --- a/templates/Froxlor/table/table.html.twig +++ b/templates/Froxlor/table/table.html.twig @@ -111,7 +111,7 @@ From 0b685d569f66d1b631683e6673c11ee4e6090e90 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 26 May 2023 13:58:41 +0200 Subject: [PATCH 10/26] start to integrate domain-deactivated flag in UI Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Domains.php | 18 +++++++++++++++--- lib/Froxlor/Api/Commands/SubDomains.php | 3 ++- lib/Froxlor/UI/Callbacks/Domain.php | 13 +++++++++---- lib/Froxlor/UI/Callbacks/Style.php | 3 ++- .../admin/domains/formfield.domains_edit.php | 8 +++++++- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 1b4bf6f2..475f458e 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -76,7 +76,7 @@ class Domains extends ApiCommand implements ResourceEntity $query_fields = []; $result_stmt = Database::prepare(" SELECT - `d`.*, `c`.`loginname`, `c`.`deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin, + `d`.*, `c`.`loginname`, `c`.`deactivated` as `customer_deactivated`, `c`.`name`, `c`.`firstname`, `c`.`company`, `c`.`standardsubdomain`, `c`.`adminid` as customeradmin, `ad`.`id` AS `aliasdomainid`, `ad`.`domain` AS `aliasdomain` FROM `" . TABLE_PANEL_DOMAINS . "` `d` LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`) @@ -1137,6 +1137,8 @@ class Domains extends ApiCommand implements ResourceEntity * (true), requires SSL * @param string $description * optional custom description (currently not used/shown in the frontend), default empty + * @param bool $deactivated + * optional, if 1 (true) the domain can be deactivated/suspended * * @access admin * @return string json-encoded array @@ -1232,6 +1234,7 @@ class Domains extends ApiCommand implements ResourceEntity $tlsv13_cipher_list = $result['tlsv13_cipher_list']; } $description = $this->getParam('description', true, $result['description']); + $deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']); // count subdomain usage of source-domain $subdomains_stmt = Database::prepare(" @@ -1832,6 +1835,7 @@ class Domains extends ApiCommand implements ResourceEntity $update_data['honorcipherorder'] = $honorcipherorder; $update_data['sessiontickets'] = $sessiontickets; $update_data['description'] = $description; + $update_data['deactivated'] = $deactivated; $update_data['id'] = $id; $update_stmt = Database::prepare(" @@ -1878,11 +1882,17 @@ class Domains extends ApiCommand implements ResourceEntity `ssl_enabled` = :sslenabled, `ssl_honorcipherorder` = :honorcipherorder, `ssl_sessiontickets` = :sessiontickets, - `description` = :description + `description` = :description, + `deactivated` = :deactivated WHERE `id` = :id "); Database::pexecute($update_stmt, $update_data, true, true); + // activate/deactivate domain-based services + if ($deactivated != $result['deactivated']) { + // @TODO + } + $_update_data['customerid'] = $customerid; $_update_data['adminid'] = $adminid; $_update_data['phpenabled'] = $phpenabled; @@ -1900,6 +1910,7 @@ class Domains extends ApiCommand implements ResourceEntity $_update_data['honorcipherorder'] = $honorcipherorder; $_update_data['sessiontickets'] = $sessiontickets; $_update_data['parentdomainid'] = $id; + $_update_data['deactivated'] = $deactivated; // if php config is to be set for all subdomains, check here $update_phpconfig = ''; @@ -1932,7 +1943,8 @@ class Domains extends ApiCommand implements ResourceEntity `ssl_cipher_list` = :ssl_cipher_list, `tlsv13_cipher_list` = :tlsv13_cipher_list, `ssl_honorcipherorder` = :honorcipherorder, - `ssl_sessiontickets` = :sessiontickets + `ssl_sessiontickets` = :sessiontickets, + `deativated` = :deactivated " . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . " WHERE `parentdomainid` = :parentdomainid "); diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index 3f95a2a1..be29ed3e 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -941,7 +941,8 @@ class SubDomains extends ApiCommand implements ResourceEntity '`d`.`parentdomainid`', '`d`.`letsencrypt`', '`d`.`registration_date`', - '`d`.`termination_date`' + '`d`.`termination_date`', + '`d`.`deactivated`' ]; } $query_fields = []; diff --git a/lib/Froxlor/UI/Callbacks/Domain.php b/lib/Froxlor/UI/Callbacks/Domain.php index 0bac2390..d56c83d6 100644 --- a/lib/Froxlor/UI/Callbacks/Domain.php +++ b/lib/Froxlor/UI/Callbacks/Domain.php @@ -51,6 +51,9 @@ class Domain public static function domainTarget(array $attributes) { if (empty($attributes['fields']['aliasdomain'])) { + if ($attributes['fields']['deactivated']) { + return lng('admin.deactivated'); + } // path or redirect if (preg_match('/^https?\:\/\//', $attributes['fields']['documentroot'])) { return [ @@ -80,7 +83,7 @@ class Domain } $result .= '' . $attributes['data'] . ''; // check for statistics if parentdomainid==0 to show stats-link for customers - if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0) { + if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0 && $attributes['fields']['deactivated'] == 0) { $statsapp = Settings::Get('system.traffictool'); $result .= ' '; } @@ -95,12 +98,12 @@ class Domain public static function canEdit(array $attributes): bool { - return (bool)$attributes['fields']['caneditdomain']; + return (bool)($attributes['fields']['caneditdomain'] && !$attributes['fields']['deactivated']); } public static function canViewLogs(array $attributes): bool { - if ((int)$attributes['fields']['email_only'] == 0) { + 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) { @@ -129,7 +132,8 @@ class Domain && UI::getCurrentUser()['dnsenabled'] == '1' && $attributes['fields']['caneditdomain'] == '1' && Settings::Get('system.bind_enable') == '1' - && Settings::Get('system.dnsenabled') == '1'; + && Settings::Get('system.dnsenabled') == '1' + && !$attributes['fields']['deactivated']; } public static function adminCanEditDNS(array $attributes): bool @@ -152,6 +156,7 @@ class Domain && (int)$attributes['fields']['caneditdomain'] == 1 && (int)$attributes['fields']['letsencrypt'] == 0 && (int)$attributes['fields']['email_only'] == 0 + && !$attributes['fields']['deactivated'] ) { return true; } diff --git a/lib/Froxlor/UI/Callbacks/Style.php b/lib/Froxlor/UI/Callbacks/Style.php index 7de6941b..6f19bee8 100644 --- a/lib/Froxlor/UI/Callbacks/Style.php +++ b/lib/Froxlor/UI/Callbacks/Style.php @@ -63,7 +63,8 @@ class Style $termination_css = 'bg-danger'; } } - return $attributes['fields']['deactivated'] ? 'bg-info' : $termination_css; + $deactivated = $attributes['fields']['deactivated'] || $attributes['fields']['customer_deactivated']; + return $deactivated ? 'bg-info' : $termination_css; } public static function resultCustomerLockedOrDeactivated(array $attributes): string diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index b6a9c308..00b00cbd 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -97,7 +97,13 @@ return [ 'type' => 'date', 'value' => $result['termination_date'], 'size' => 10 - ] + ], + 'deactivated' => [ + 'label' => lng('admin.deactivated'), + 'type' => 'checkbox', + 'value' => '1', + 'checked' => $result['deactivated'] + ], ] ], 'section_e' => [ From 63d81201de899fde18404fc3d2de243d967df5d9 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 26 May 2023 14:02:09 +0200 Subject: [PATCH 11/26] fix typo Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Domains.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 475f458e..22639b7d 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1944,7 +1944,7 @@ class Domains extends ApiCommand implements ResourceEntity `tlsv13_cipher_list` = :tlsv13_cipher_list, `ssl_honorcipherorder` = :honorcipherorder, `ssl_sessiontickets` = :sessiontickets, - `deativated` = :deactivated + `deactivated` = :deactivated " . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . " WHERE `parentdomainid` = :parentdomainid "); From ca5f36d91278f4ece572331722a6a87dd873dbd4 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 26 May 2023 21:24:08 +0200 Subject: [PATCH 12/26] corrected language index in system-settings, fixes #1145 Signed-off-by: Michael Kaufmann --- lng/de.lng.php | 8 ++------ lng/en.lng.php | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lng/de.lng.php b/lng/de.lng.php index ff39aa19..616f92aa 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -2017,12 +2017,8 @@ Vielen Dank, Ihr Administrator', 'description' => 'Der Inhalt dieses Feldes wird direkt in den IP/Port-vHost-Container übernommen. Die folgenden Variablen können verwendet werden:
{DOMAIN}, {DOCROOT}, {CUSTOMER}, {IP}, {PORT}, {SCHEME}, {FPMSOCKET} (wenn zutreffend)

ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Der Webserver könnte nicht mehr starten!', ], 'includedefault_sslvhostconf' => 'Nicht-SSL vHost-Einstellungen in SSL-vHost inkludieren', - 'apply_specialsettings_default' => [ - 'title' => 'Standardwert für "Übernehme Einstellungen für alle Subdomains (*.beispiel.de)\' Einstellung beim Bearbeiten einer Domain', - ], - 'apply_phpconfigs_default' => [ - 'title' => 'Standardwert für "PHP-Config für alle Subdomains übernehmen:\' Einstellung beim Bearbeiten einer Domain', - ], + 'apply_specialsettings_default' => 'Standardwert für "Übernehme Einstellungen für alle Subdomains (*.beispiel.de)" Einstellung beim Bearbeiten einer Domain', + 'apply_phpconfigs_default' => 'Standardwert für "PHP-Config für alle Subdomains übernehmen:" Einstellung beim Bearbeiten einer Domain', 'awstats' => [ 'logformat' => [ 'title' => 'LogFormat Einstellung', diff --git a/lng/en.lng.php b/lng/en.lng.php index f92730a0..45925fc2 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -2136,12 +2136,8 @@ Yours sincerely, your administrator', 'description' => 'The content of this field will be included into this ip/port vHost container directly. You can use the following variables:
{DOMAIN}, {DOCROOT}, {CUSTOMER}, {IP}, {PORT}, {SCHEME}, {FPMSOCKET} (if applicable)
Attention: The code won\'t be checked for any errors. If it contains errors, webserver might not start again!', ], 'includedefault_sslvhostconf' => 'Include non-SSL vHost-settings in SSL-vHost', - 'apply_specialsettings_default' => [ - 'title' => 'Default value for "Apply specialsettings to all subdomains (*.example.com)\' setting when editing a domain', - ], - 'apply_phpconfigs_default' => [ - 'title' => 'Default value for "Apply php-config to all subdomains:\' setting when editing a domain', - ], + 'apply_specialsettings_default' => 'Default value for "Apply specialsettings to all subdomains (*.example.com)" setting when editing a domain', + 'apply_phpconfigs_default' => 'Default value for "Apply php-config to all subdomains" setting when editing a domain', 'awstats' => [ 'logformat' => [ 'title' => 'LogFormat setting', From a7dd5f4685c2a480972ca30b5952313111d5c55b Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 May 2023 10:46:28 +0200 Subject: [PATCH 13/26] show 0 value of resource-fields if value is empty, fixes #1149 Signed-off-by: Michael Kaufmann --- .../admin/admin/formfield.admin_edit.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/formfields/admin/admin/formfield.admin_edit.php b/lib/formfields/admin/admin/formfield.admin_edit.php index 3d641103..d5cf9493 100644 --- a/lib/formfields/admin/admin/formfield.admin_edit.php +++ b/lib/formfields/admin/admin/formfield.admin_edit.php @@ -133,7 +133,7 @@ return [ 'customers' => [ 'label' => lng('admin.customers'), 'type' => 'textul', - 'value' => $result['customers'], + 'value' => empty($result['customers']) ? '0' : $result['customers'], 'maxlength' => 9, 'mandatory' => true ], @@ -146,7 +146,7 @@ return [ 'domains' => [ 'label' => lng('admin.domains'), 'type' => 'textul', - 'value' => $result['domains'], + 'value' => empty($result['domains']) ? '0' : $result['domains'], 'maxlength' => 9, 'mandatory' => true ], @@ -159,49 +159,49 @@ return [ 'diskspace' => [ 'label' => lng('customer.diskspace') . ' (' . lng('customer.mib') . ')', 'type' => 'textul', - 'value' => $result['diskspace'], + 'value' => empty($result['diskspace']) ? '0' : $result['diskspace'], 'maxlength' => 6, 'mandatory' => true ], 'traffic' => [ 'label' => lng('customer.traffic') . ' (' . lng('customer.gib') . ')', 'type' => 'textul', - 'value' => $result['traffic'], + 'value' => empty($result['traffic']) ? '0' : $result['traffic'], 'maxlength' => 4, 'mandatory' => true ], 'subdomains' => [ 'label' => lng('customer.subdomains'), 'type' => 'textul', - 'value' => $result['subdomains'], + 'value' => empty($result['subdomains']) ? '0' : $result['subdomains'], 'maxlength' => 9, 'mandatory' => true ], 'emails' => [ 'label' => lng('customer.emails'), 'type' => 'textul', - 'value' => $result['emails'], + 'value' => empty($result['emails']) ? '0' : $result['emails'], 'maxlength' => 9, 'mandatory' => true ], 'email_accounts' => [ 'label' => lng('customer.accounts'), 'type' => 'textul', - 'value' => $result['email_accounts'], + 'value' => empty($result['email_accounts']) ? '0' : $result['email_accounts'], 'maxlength' => 9, 'mandatory' => true ], 'email_forwarders' => [ 'label' => lng('customer.forwarders'), 'type' => 'textul', - 'value' => $result['email_forwarders'], + 'value' => empty($result['email_forwarders']) ? '0' : $result['email_forwarders'], 'maxlength' => 9, 'mandatory' => true ], 'email_quota' => [ 'label' => lng('customer.email_quota') . ' (' . lng('customer.mib') . ')', 'type' => 'textul', - 'value' => $result['email_quota'], + 'value' => empty($result['email_quota']) ? '0' : $result['email_quota'], 'maxlength' => 9, 'visible' => Settings::Get('system.mail_quota_enabled') == '1', 'mandatory' => true @@ -209,13 +209,13 @@ return [ 'ftps' => [ 'label' => lng('customer.ftps'), 'type' => 'textul', - 'value' => $result['ftps'], + 'value' => empty($result['ftps']) ? '0' : $result['ftps'], 'maxlength' => 9 ], 'mysqls' => [ 'label' => lng('customer.mysqls'), 'type' => 'textul', - 'value' => $result['mysqls'], + 'value' => empty($result['mysqls']) ? '0' : $result['mysqls'], 'maxlength' => 9, 'mandatory' => true ] From 9facaee809250bb9d0a0a3ad49f08353b6531fb8 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 May 2023 15:49:06 +0200 Subject: [PATCH 14/26] re-enable fcgid/php-fpm activation-validate-check Signed-off-by: Michael Kaufmann --- lib/Froxlor/Validate/Check.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Froxlor/Validate/Check.php b/lib/Froxlor/Validate/Check.php index 5841444f..cb113c72 100644 --- a/lib/Froxlor/Validate/Check.php +++ b/lib/Froxlor/Validate/Check.php @@ -52,16 +52,16 @@ class Check ]; $check_array = [ - 'system_mod_fcgid_enabled' => [ - 'other_post_field' => 'system_phpfpm_enabled', + 'system_mod_fcgid' => [ + 'other_post_field' => 'phpfpm_enabled', 'other_enabled' => 'phpfpm.enabled', 'other_enabled_lng' => 'phpfpmstillenabled', 'deactivate' => [ 'phpfpm.enabled_ownvhost' => 0 ] ], - 'system_phpfpm_enabled' => [ - 'other_post_field' => 'system_mod_fcgid_enabled', + 'phpfpm_enabled' => [ + 'other_post_field' => 'system_mod_fcgid', 'other_enabled' => 'system.mod_fcgid', 'other_enabled_lng' => 'fcgidstillenabled', 'deactivate' => [ From 688994e40c3fe31dacaabeb39cf979a0bc11dddc Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 29 May 2023 20:52:57 +0200 Subject: [PATCH 15/26] idna encode umlaut-emailaddresses when adding email-forwarder Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/EmailForwarders.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Froxlor/Api/Commands/EmailForwarders.php b/lib/Froxlor/Api/Commands/EmailForwarders.php index 520fd05c..28eb9226 100644 --- a/lib/Froxlor/Api/Commands/EmailForwarders.php +++ b/lib/Froxlor/Api/Commands/EmailForwarders.php @@ -77,6 +77,11 @@ class EmailForwarders extends ApiCommand implements ResourceEntity $idna_convert = new IdnaWrapper(); $destination = $idna_convert->encode($destination); + if (!empty($emailaddr)) { + $idna_convert = new IdnaWrapper(); + $emailaddr = $idna_convert->encode($emailaddr); + } + $result = $this->apiCall('Emails.get', [ 'id' => $id, 'emailaddr' => $emailaddr From c236d9eaab03bf4a69ccf8b75ea9ce1992ba75cd Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 2 Jun 2023 20:13:36 +0200 Subject: [PATCH 16/26] set version to 2.0.20 for upcoming release Signed-off-by: Michael Kaufmann --- install/froxlor.sql.php | 4 ++-- install/updates/froxlor/update_2.x.inc.php | 5 +++++ lib/Froxlor/Froxlor.php | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 62c626f2..7539b493 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -697,7 +697,7 @@ opcache.validate_timestamps'), ('system', 'distribution', ''), ('system', 'update_channel', 'stable'), ('system', 'updatecheck_data', ''), - ('system', 'update_notify_last', '2.0.19'), + ('system', 'update_notify_last', '2.0.20'), ('system', 'traffictool', 'goaccess'), ('system', 'req_limit_per_interval', 60), ('system', 'req_limit_interval', 60), @@ -744,7 +744,7 @@ opcache.validate_timestamps'), ('panel', 'logo_overridetheme', '0'), ('panel', 'logo_overridecustom', '0'), ('panel', 'settings_mode', '0'), - ('panel', 'version', '2.0.19'), + ('panel', 'version', '2.0.20'), ('panel', 'db_version', '202304260'); diff --git a/install/updates/froxlor/update_2.x.inc.php b/install/updates/froxlor/update_2.x.inc.php index 228fdac1..7e3541df 100644 --- a/install/updates/froxlor/update_2.x.inc.php +++ b/install/updates/froxlor/update_2.x.inc.php @@ -492,3 +492,8 @@ if (Froxlor::isFroxlorVersion('2.0.18')) { Update::showUpdateStep("Updating from 2.0.18 to 2.0.19", false); Froxlor::updateToVersion('2.0.19'); } + +if (Froxlor::isFroxlorVersion('2.0.19')) { + Update::showUpdateStep("Updating from 2.0.19 to 2.0.20", false); + Froxlor::updateToVersion('2.0.20'); +} diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 6f05abf1..f8169694 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -31,7 +31,7 @@ final class Froxlor { // Main version variable - const VERSION = '2.0.19'; + const VERSION = '2.0.20'; // Database version (YYYYMMDDC where C is a daily counter) const DBVERSION = '202304260'; From 3940c1429db7aad89f7d2711c69975fc158c8566 Mon Sep 17 00:00:00 2001 From: Grigory Morozov Date: Mon, 5 Jun 2023 13:06:44 +0700 Subject: [PATCH 17/26] Correcting Nginx location match, fixes #1153 --- lib/Froxlor/Cron/Http/Nginx.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index 51230334..76ad0471 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -225,7 +225,7 @@ class Nginx extends HttpConfigBase $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; // protect bin/ - $this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . 'location ~ ^' . rtrim($relpath, "/") . '/(bin|cache|logs|tests|vendor) {' . "\n"; $this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n"; $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; } From e1e7bc7b42b40d07887b92cbfe9d2d5c920e9bdd Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 5 Jun 2023 09:01:41 +0200 Subject: [PATCH 18/26] set fastcgi_ipcdir according to webserver after installation (regardless of using phpfpm) Signed-off-by: Michael Kaufmann --- lib/configfiles/bionic.xml | 2 ++ lib/configfiles/bookworm.xml | 2 ++ lib/configfiles/bullseye.xml | 2 ++ lib/configfiles/buster.xml | 2 ++ lib/configfiles/focal.xml | 4 +++- lib/configfiles/gentoo.xml | 2 ++ lib/configfiles/jammy.xml | 2 ++ 7 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/configfiles/bionic.xml b/lib/configfiles/bionic.xml index 22dd1233..76ccc55c 100644 --- a/lib/configfiles/bionic.xml +++ b/lib/configfiles/bionic.xml @@ -10,11 +10,13 @@ + + diff --git a/lib/configfiles/bookworm.xml b/lib/configfiles/bookworm.xml index f82d87d4..d0d89f4b 100644 --- a/lib/configfiles/bookworm.xml +++ b/lib/configfiles/bookworm.xml @@ -10,11 +10,13 @@ + + diff --git a/lib/configfiles/bullseye.xml b/lib/configfiles/bullseye.xml index 2e8fe249..1b7d352d 100644 --- a/lib/configfiles/bullseye.xml +++ b/lib/configfiles/bullseye.xml @@ -10,11 +10,13 @@ + + diff --git a/lib/configfiles/buster.xml b/lib/configfiles/buster.xml index 17c988e8..82d2f4b2 100644 --- a/lib/configfiles/buster.xml +++ b/lib/configfiles/buster.xml @@ -10,11 +10,13 @@ + + diff --git a/lib/configfiles/focal.xml b/lib/configfiles/focal.xml index 862a80b6..96563815 100644 --- a/lib/configfiles/focal.xml +++ b/lib/configfiles/focal.xml @@ -9,12 +9,14 @@ - + + + + diff --git a/lib/configfiles/gentoo.xml b/lib/configfiles/gentoo.xml index aecee819..697c8924 100644 --- a/lib/configfiles/gentoo.xml +++ b/lib/configfiles/gentoo.xml @@ -17,11 +17,13 @@ + + diff --git a/lib/configfiles/jammy.xml b/lib/configfiles/jammy.xml index c7f7172e..1ffcf68b 100644 --- a/lib/configfiles/jammy.xml +++ b/lib/configfiles/jammy.xml @@ -10,11 +10,13 @@ + + From 9ddf24539e60b2d880f3a255f60707ffed9f2070 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 5 Jun 2023 12:10:39 +0200 Subject: [PATCH 19/26] remove hidden fields from login/passwd-reset; refs #1102 Signed-off-by: Michael Kaufmann --- index.php | 33 ++++++++++++++----------- templates/Froxlor/login/fpwd.html.twig | 4 +-- templates/Froxlor/login/login.html.twig | 3 --- templates/Froxlor/login/rpwd.html.twig | 2 -- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/index.php b/index.php index d59146e3..faa69323 100644 --- a/index.php +++ b/index.php @@ -161,7 +161,7 @@ if ($action == '2fa_entercode') { ]); exit(); } elseif ($action == 'login') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (!empty($_POST)) { $loginname = Validate::validate($_POST['loginname'], 'loginname'); $password = Validate::validate($_POST['password'], 'password'); @@ -431,13 +431,13 @@ if ($action == '2fa_entercode') { } $lastqrystr = ""; if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") { - $lastqrystr = htmlspecialchars($_REQUEST['qrystr'], ENT_QUOTES); + $lastqrystr = urlencode($_REQUEST['qrystr']); } + $_SESSION['lastscript'] = $lastscript; + $_SESSION['lastqrystr'] = $lastqrystr; UI::view('login/login.html.twig', [ 'pagetitle' => 'Login', - 'lastscript' => $lastscript, - 'lastqrystr' => $lastqrystr, 'upd_in_progress' => $update_in_progress, 'message' => $message, 'successmsg' => $successmessage @@ -449,7 +449,7 @@ if ($action == 'forgotpwd') { $adminchecked = false; $message = ''; - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (!empty($_POST)) { $loginname = Validate::validate($_POST['loginname'], 'loginname'); $email = Validate::validateEmail($_POST['loginemail']); $result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "` @@ -633,7 +633,7 @@ if ($action == 'forgotpwd') { UI::view('login/fpwd.html.twig', [ 'pagetitle' => lng('login.presend'), - 'action' => $action, + 'formaction' => 'index.php?action='.$action, 'message' => $message, ]); } @@ -656,7 +656,7 @@ if ($action == 'resetpwd') { $check = substr($activationcode, 40, 10); if (substr(md5($third . $timestamp), 0, 10) == $check && $timestamp >= time() - 86400) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (!empty($_POST)) { $stmt = Database::prepare("SELECT `userid`, `admin` FROM `" . TABLE_PANEL_ACTIVATION . "` WHERE `activationcode` = :activationcode"); $result = Database::pexecute_first($stmt, [ @@ -746,29 +746,34 @@ function finishLogin($userinfo) } $qryparams = []; - if (isset($_POST['qrystr']) && $_POST['qrystr'] != "") { - parse_str(urldecode($_POST['qrystr']), $qryparams); + if (isset($_SESSION['lastqrystr']) && !empty($_SESSION['lastqrystr'])) { + parse_str(urldecode($_SESSION['lastqrystr']), $qryparams); + unset($_SESSION['lastqrystr']); } if ($userinfo['adminsession'] == '1') { if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { Response::redirectTo('admin_updates.php?page=overview'); } else { - if (isset($_POST['script']) && $_POST['script'] != "") { - if (preg_match("/customer\_/", $_POST['script']) === 1) { + if (isset($_SESSION['lastscript']) && !empty($_SESSION['lastscript'])) { + $lastscript = $_SESSION['lastscript']; + unset($_SESSION['lastscript']); + if (preg_match("/customer\_/", $lastscript) === 1) { Response::redirectTo('admin_customers.php', [ "page" => "customers" ]); } else { - Response::redirectTo($_POST['script'], $qryparams); + Response::redirectTo($lastscript, $qryparams); } } else { Response::redirectTo('admin_index.php', $qryparams); } } } else { - if (isset($_POST['script']) && $_POST['script'] != "") { - Response::redirectTo($_POST['script'], $qryparams); + if (isset($_SESSION['lastscript']) && !empty($_SESSION['lastscript'])) { + $lastscript = $_SESSION['lastscript']; + unset($_SESSION['lastscript']); + Response::redirectTo($lastscript, $qryparams); } else { Response::redirectTo('customer_index.php', $qryparams); } diff --git a/templates/Froxlor/login/fpwd.html.twig b/templates/Froxlor/login/fpwd.html.twig index e20b3ee0..6832c5ab 100644 --- a/templates/Froxlor/login/fpwd.html.twig +++ b/templates/Froxlor/login/fpwd.html.twig @@ -3,7 +3,7 @@ {% block content %}
-
+ Froxlor Server Management Panel
@@ -38,8 +38,6 @@
- -
diff --git a/templates/Froxlor/login/login.html.twig b/templates/Froxlor/login/login.html.twig index f78bc8e9..afcaf4df 100644 --- a/templates/Froxlor/login/login.html.twig +++ b/templates/Froxlor/login/login.html.twig @@ -39,9 +39,6 @@
- - -
diff --git a/templates/Froxlor/login/rpwd.html.twig b/templates/Froxlor/login/rpwd.html.twig index ebe4fdec..a24653dc 100644 --- a/templates/Froxlor/login/rpwd.html.twig +++ b/templates/Froxlor/login/rpwd.html.twig @@ -30,8 +30,6 @@
- -
From 826ae36647066ba00f4b62e1dfe9dc1775e855ba Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 5 Jun 2023 12:13:38 +0200 Subject: [PATCH 20/26] adjust log-levels in API methods Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Admins.php | 6 +-- lib/Froxlor/Api/Commands/Certificates.php | 6 +-- lib/Froxlor/Api/Commands/Cronjobs.php | 4 +- lib/Froxlor/Api/Commands/CustomerBackups.php | 2 +- lib/Froxlor/Api/Commands/Customers.php | 8 ++-- lib/Froxlor/Api/Commands/DirOptions.php | 10 ++--- lib/Froxlor/Api/Commands/DirProtections.php | 10 ++--- lib/Froxlor/Api/Commands/DomainZones.php | 2 +- lib/Froxlor/Api/Commands/Domains.php | 6 +-- lib/Froxlor/Api/Commands/EmailAccounts.php | 6 +-- lib/Froxlor/Api/Commands/EmailDomains.php | 2 +- lib/Froxlor/Api/Commands/EmailForwarders.php | 4 +- lib/Froxlor/Api/Commands/Emails.php | 10 ++--- lib/Froxlor/Api/Commands/FpmDaemons.php | 8 ++-- lib/Froxlor/Api/Commands/Froxlor.php | 4 +- lib/Froxlor/Api/Commands/Ftps.php | 12 +++--- lib/Froxlor/Api/Commands/HostingPlans.php | 8 ++-- lib/Froxlor/Api/Commands/IpsAndPorts.php | 4 +- lib/Froxlor/Api/Commands/MysqlServer.php | 44 ++++++++++++-------- lib/Froxlor/Api/Commands/Mysqls.php | 6 +-- lib/Froxlor/Api/Commands/PhpSettings.php | 8 ++-- lib/Froxlor/Api/Commands/SubDomains.php | 4 +- lib/Froxlor/Api/Commands/SysLog.php | 2 +- lib/Froxlor/Api/Commands/Traffic.php | 2 +- 24 files changed, 94 insertions(+), 84 deletions(-) diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index ae7d12c3..10175ddf 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -95,7 +95,7 @@ class Admins extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list admins"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list admins"); $query_fields = []; $result_stmt = Database::prepare(" SELECT * @@ -407,7 +407,7 @@ class Admins extends ApiCommand implements ResourceEntity ]; $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get admin '" . $result['loginname'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get admin '" . $result['loginname'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'"); @@ -705,7 +705,7 @@ class Admins extends ApiCommand implements ResourceEntity WHERE `adminid` = :adminid "); Database::pexecute($upd_stmt, $upd_data, true, true); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] edited admin '" . $result['loginname'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] edited admin '" . $result['loginname'] . "'"); // get all admin-data for return-array $result = $this->apiCall('Admins.get', [ diff --git a/lib/Froxlor/Api/Commands/Certificates.php b/lib/Froxlor/Api/Commands/Certificates.php index 3ad44633..df0e7619 100644 --- a/lib/Froxlor/Api/Commands/Certificates.php +++ b/lib/Froxlor/Api/Commands/Certificates.php @@ -97,7 +97,7 @@ class Certificates extends ApiCommand implements ResourceEntity } if (!$has_cert) { $this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ssl-certificate for '" . $domain['domain'] . "'"); $result = $this->apiCall('Certificates.get', [ 'id' => $domain['id'] ]); @@ -248,7 +248,7 @@ class Certificates extends ApiCommand implements ResourceEntity $ssl_ca_file = $this->getParam('ssl_ca_file', true, ''); $ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, ''); $this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, false); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ssl-certificate for '" . $domain['domain'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ssl-certificate for '" . $domain['domain'] . "'"); $result = $this->apiCall('Certificates.get', [ 'id' => $domain['id'] ]); @@ -470,7 +470,7 @@ class Certificates extends ApiCommand implements ResourceEntity if ($chk['letsencrypt'] == '1') { Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $chk['domain']); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] removed ssl-certificate for '" . $chk['domain'] . "'"); return $this->response($result); } throw new Exception("Unable to determine SSL certificate. Maybe no access?", 406); diff --git a/lib/Froxlor/Api/Commands/Cronjobs.php b/lib/Froxlor/Api/Commands/Cronjobs.php index d9678763..73d0c933 100644 --- a/lib/Froxlor/Api/Commands/Cronjobs.php +++ b/lib/Froxlor/Api/Commands/Cronjobs.php @@ -147,7 +147,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity // insert task to re-generate the cron.d-file Cronjob::inserttask(TaskId::REBUILD_CRON); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); $result = $this->apiCall('Cronjobs.get', [ 'id' => $id ]); @@ -177,7 +177,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin()) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list cronjobs"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list cronjobs"); $query_fields = []; $result_stmt = Database::prepare(" SELECT `c`.* FROM `" . TABLE_PANEL_CRONRUNS . "` `c` " . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit()); diff --git a/lib/Froxlor/Api/Commands/CustomerBackups.php b/lib/Froxlor/Api/Commands/CustomerBackups.php index efbbaa66..5dbc9392 100644 --- a/lib/Froxlor/Api/Commands/CustomerBackups.php +++ b/lib/Froxlor/Api/Commands/CustomerBackups.php @@ -194,7 +194,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity $result[] = $entry; } } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list customer-backups"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups"); return $this->response([ 'count' => count($result), 'list' => $result diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index e4c23e6c..b6ac3c89 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -895,7 +895,7 @@ class Customers extends ApiCommand implements ResourceEntity $result['dbspace_used'] = 0; } } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get customer '" . $result['loginname'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get customer '" . $result['loginname'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "loginname '" . $loginname . "'"); @@ -1327,7 +1327,7 @@ class Customers extends ApiCommand implements ResourceEntity 'vu' => $valid_until ], true, true); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'"); Cronjob::inserttask(TaskId::REBUILD_VHOST); } @@ -1538,7 +1538,7 @@ class Customers extends ApiCommand implements ResourceEntity Database::query($admin_update_query); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited user '" . $result['loginname'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited user '" . $result['loginname'] . "'"); /* * move customer to another admin/reseller; #1166 @@ -1911,7 +1911,7 @@ class Customers extends ApiCommand implements ResourceEntity // now, recalculate the resource-usage for the old and the new admin User::updateCounters(false); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] moved user '" . $c_result['loginname'] . "' from admin/reseller '" . $c_result['adminname'] . " to admin/reseller '" . $a_result['loginname'] . "'"); $result = $this->apiCall('Customers.get', [ 'id' => $c_result['customerid'] diff --git a/lib/Froxlor/Api/Commands/DirOptions.php b/lib/Froxlor/Api/Commands/DirOptions.php index 96a89265..f55ef889 100644 --- a/lib/Froxlor/Api/Commands/DirOptions.php +++ b/lib/Froxlor/Api/Commands/DirOptions.php @@ -144,7 +144,7 @@ class DirOptions extends ApiCommand implements ResourceEntity ]; Database::pexecute($stmt, $params, true, true); $id = Database::lastInsertId(); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-option for '" . $userpath . "'"); Cronjob::inserttask(TaskId::REBUILD_VHOST); $result = $this->apiCall('DirOptions.get', [ @@ -247,7 +247,7 @@ class DirOptions extends ApiCommand implements ResourceEntity $params['id'] = $id; $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory options for '" . $result['path'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory options for '" . $result['path'] . "'"); return $this->response($result); } $key = "id #" . $id; @@ -331,7 +331,7 @@ class DirOptions extends ApiCommand implements ResourceEntity "id" => $id ]; Database::pexecute($stmt, $params, true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited directory options for '" . str_replace($customer['documentroot'], '/', $result['path']) . "'"); } $result = $this->apiCall('DirOptions.get', [ @@ -379,7 +379,7 @@ class DirOptions extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-options"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-options"); return $this->response([ 'count' => count($result), 'list' => $result @@ -478,7 +478,7 @@ class DirOptions extends ApiCommand implements ResourceEntity "customerid" => $customer_data['customerid'], "id" => $id ], true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'"); Cronjob::inserttask(TaskId::REBUILD_VHOST); return $this->response($result); } diff --git a/lib/Froxlor/Api/Commands/DirProtections.php b/lib/Froxlor/Api/Commands/DirProtections.php index 690adf8b..b21bdd6e 100644 --- a/lib/Froxlor/Api/Commands/DirProtections.php +++ b/lib/Froxlor/Api/Commands/DirProtections.php @@ -129,7 +129,7 @@ class DirProtections extends ApiCommand implements ResourceEntity ]; Database::pexecute($stmt, $params, true, true); $id = Database::lastInsertId(); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added directory-protection for '" . $username . " (" . $path . ")'"); Cronjob::inserttask(TaskId::REBUILD_VHOST); $result = $this->apiCall('DirProtections.get', [ @@ -196,7 +196,7 @@ class DirProtections extends ApiCommand implements ResourceEntity $params['idun'] = ($id <= 0 ? $username : $id); $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get directory protection for '" . $result['path'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get directory protection for '" . $result['path'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "username '" . $username . "'"); @@ -279,7 +279,7 @@ class DirProtections extends ApiCommand implements ResourceEntity Cronjob::inserttask(TaskId::REBUILD_VHOST); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'"); $result = $this->apiCall('DirProtections.get', [ 'id' => $result['id'] ]); @@ -325,7 +325,7 @@ class DirProtections extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list directory-protections"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list directory-protections"); return $this->response([ 'count' => count($result), 'list' => $result @@ -413,7 +413,7 @@ class DirProtections extends ApiCommand implements ResourceEntity "id" => $id ]); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'"); Cronjob::inserttask(TaskId::REBUILD_VHOST); return $this->response($result); } diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index e8e2163e..3975fd4a 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -413,7 +413,7 @@ class DomainZones extends ApiCommand implements ResourceEntity $zone = Dns::createDomainZone($id); $zonefile = (string)$zone; - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get dns-zone for '" . $result['domain'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get dns-zone for '" . $result['domain'] . "'"); return $this->response(explode("\n", $zonefile)); } diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index ea318e97..f3a331e8 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -898,7 +898,7 @@ class Domains extends ApiCommand implements ResourceEntity $result['ipsandports'] = $this->getIpsForDomain($result['id']); } $result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get domain '" . $result['domain'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get domain '" . $result['domain'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'"); @@ -1801,7 +1801,7 @@ class Domains extends ApiCommand implements ResourceEntity Database::pexecute($upd_stmt, [ 'id' => $id ], true, true); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] removed specialsettings on all subdomains of domain #" . $id); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] removed specialsettings on all subdomains of domain #" . $id); } $wwwserveralias = ($serveraliasoption == '1') ? '1' : '0'; @@ -2221,7 +2221,7 @@ class Domains extends ApiCommand implements ResourceEntity // remove domain from acme.sh / lets encrypt if used Cronjob::inserttask(TaskId::DELETE_DOMAIN_SSL, $result['domain']); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted domain/subdomains (#" . $result['id'] . ")"); User::updateCounters(); Cronjob::inserttask(TaskId::REBUILD_VHOST); // Using nameserver, insert a task which rebuilds the server config diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index feb0cd9a..605a6daa 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -311,7 +311,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity } } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email account for '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email account for '" . $result['email_full'] . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $result['email_full'] ]); @@ -460,7 +460,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity Admins::increaseUsage($customer['adminid'], 'email_quota_used', '', ($quota - $result['quota'])); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated email account '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated email account '" . $result['email_full'] . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $result['email_full'] ]); @@ -566,7 +566,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity Customers::decreaseUsage($customer['customerid'], 'email_accounts_used'); Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $quota); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account for '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email account for '" . $result['email_full'] . "'"); return $this->response($result); } } diff --git a/lib/Froxlor/Api/Commands/EmailDomains.php b/lib/Froxlor/Api/Commands/EmailDomains.php index 0e7f0b37..8fadf3a0 100644 --- a/lib/Froxlor/Api/Commands/EmailDomains.php +++ b/lib/Froxlor/Api/Commands/EmailDomains.php @@ -89,7 +89,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-domains"); return $this->response([ 'count' => count($result), diff --git a/lib/Froxlor/Api/Commands/EmailForwarders.php b/lib/Froxlor/Api/Commands/EmailForwarders.php index 28eb9226..79c178b0 100644 --- a/lib/Froxlor/Api/Commands/EmailForwarders.php +++ b/lib/Froxlor/Api/Commands/EmailForwarders.php @@ -121,7 +121,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity // update customer usage Customers::increaseUsage($customer['customerid'], 'email_forwarders_used'); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email forwarder for '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email forwarder for '" . $result['email_full'] . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $result['email_full'] @@ -298,7 +298,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity // update customer usage Customers::decreaseUsage($customer['customerid'], 'email_forwarders_used'); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email forwarder for '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted email forwarder for '" . $result['email_full'] . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $result['email_full'] diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 3ef990c6..221efa9b 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -159,7 +159,7 @@ class Emails extends ApiCommand implements ResourceEntity // update customer usage Customers::increaseUsage($customer['customerid'], 'emails_used'); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $email_full @@ -199,7 +199,7 @@ class Emails extends ApiCommand implements ResourceEntity ); $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'"); @@ -294,7 +294,7 @@ class Emails extends ApiCommand implements ResourceEntity "id" => $id ]; Database::pexecute($stmt, $params, true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'"); $result = $this->apiCall('Emails.get', [ 'emailaddr' => $result['email_full'] @@ -340,7 +340,7 @@ class Emails extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list email-addresses"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses"); return $this->response([ 'count' => count($result), 'list' => $result @@ -445,7 +445,7 @@ class Emails extends ApiCommand implements ResourceEntity ], true, true); Customers::decreaseUsage($customer['customerid'], 'emails_used'); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email address '" . $result['email_full'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted email address '" . $result['email_full'] . "'"); return $this->response($result); } } diff --git a/lib/Froxlor/Api/Commands/FpmDaemons.php b/lib/Froxlor/Api/Commands/FpmDaemons.php index a0577ad4..26d4d493 100644 --- a/lib/Froxlor/Api/Commands/FpmDaemons.php +++ b/lib/Froxlor/Api/Commands/FpmDaemons.php @@ -64,7 +64,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin()) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list fpm-daemons"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list fpm-daemons"); $query_fields = []; $result_stmt = Database::prepare(" SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "`" . $this->getSearchWhere($query_fields) . $this->getOrderBy() . $this->getLimit()); @@ -258,7 +258,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity $id = Database::lastInsertId(); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'"); $result = $this->apiCall('FpmDaemons.get', [ 'id' => $id ]); @@ -384,7 +384,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity Database::pexecute($upd_stmt, $upd_data, true, true); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); $result = $this->apiCall('FpmDaemons.get', [ 'id' => $id ]); @@ -433,7 +433,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity ], true, true); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'"); return $this->response($result); } throw new Exception("Not allowed to execute given command.", 403); diff --git a/lib/Froxlor/Api/Commands/Froxlor.php b/lib/Froxlor/Api/Commands/Froxlor.php index 690b5880..378f84c5 100644 --- a/lib/Froxlor/Api/Commands/Froxlor.php +++ b/lib/Froxlor/Api/Commands/Froxlor.php @@ -72,7 +72,7 @@ class Froxlor extends ApiCommand if (empty($uc_data) || empty($response) || $uc_data['ts'] + self::UPDATE_CHECK_INTERVAL < time() || $uc_data['channel'] != Settings::Get('system.update_channel') || $force_ucheck) { // log our actions - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] checking for updates"); // check for new version $aucheck = AutoUpdate::checkVersion(); @@ -142,7 +142,7 @@ class Froxlor extends ApiCommand { if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) { $json_str = $this->getParam('json_str'); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "User " . $this->getUserDetail('loginname') . " imported settings"); try { SImExporter::import($json_str); Cronjob::inserttask(TaskId::REBUILD_VHOST); diff --git a/lib/Froxlor/Api/Commands/Ftps.php b/lib/Froxlor/Api/Commands/Ftps.php index 76826087..41dc8cb9 100644 --- a/lib/Froxlor/Api/Commands/Ftps.php +++ b/lib/Froxlor/Api/Commands/Ftps.php @@ -257,7 +257,7 @@ class Ftps extends ApiCommand implements ResourceEntity Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber'); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-account '" . $username . " (" . $path . ")'"); Cronjob::inserttask(TaskId::CREATE_FTP); if ($sendinfomail == 1) { @@ -302,7 +302,7 @@ class Ftps extends ApiCommand implements ResourceEntity $this->mailer()->clearAddresses(); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added ftp-user '" . $username . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added ftp-user '" . $username . "'"); $result = $this->apiCall('Ftps.get', [ 'username' => $username @@ -367,7 +367,7 @@ class Ftps extends ApiCommand implements ResourceEntity $params['idun'] = ($id <= 0 ? $username : $id); $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get ftp-user '" . $result['username'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get ftp-user '" . $result['username'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "username '" . $username . "'"); @@ -453,7 +453,7 @@ class Ftps extends ApiCommand implements ResourceEntity "id" => $id, "password" => $cryptPassword ], true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account password for '" . $result['username'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account password for '" . $result['username'] . "'"); } // path update? @@ -471,7 +471,7 @@ class Ftps extends ApiCommand implements ResourceEntity "customerid" => $customer['customerid'], "id" => $id ], true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated ftp-account homdir for '" . $result['username'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated ftp-account homdir for '" . $result['username'] . "'"); } } // it's the task for "new ftp" but that will @@ -533,7 +533,7 @@ class Ftps extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list ftp-users"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list ftp-users"); return $this->response([ 'count' => count($result), 'list' => $result diff --git a/lib/Froxlor/Api/Commands/HostingPlans.php b/lib/Froxlor/Api/Commands/HostingPlans.php index 7fde4652..971307b5 100644 --- a/lib/Froxlor/Api/Commands/HostingPlans.php +++ b/lib/Froxlor/Api/Commands/HostingPlans.php @@ -61,7 +61,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin()) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list hosting-plans"); $query_fields = []; $result_stmt = Database::prepare(" SELECT p.*, a.loginname as adminname @@ -227,7 +227,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity 'valuearr' => json_encode($value_arr) ]; Database::pexecute($ins_stmt, $ins_data, true, true); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] added hosting-plan '" . $name . "'"); $result = $this->apiCall('HostingPlans.get', [ 'planname' => $name ]); @@ -264,7 +264,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity } $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get hosting-plan '" . $result['name'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'"); @@ -414,7 +414,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity 'id' => $id ]; Database::pexecute($upd_stmt, $update_data, true, true); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] updated hosting-plan '" . $result['name'] . "'"); return $this->response($update_data); } throw new Exception("Not allowed to execute given command.", 403); diff --git a/lib/Froxlor/Api/Commands/IpsAndPorts.php b/lib/Froxlor/Api/Commands/IpsAndPorts.php index d3dfe6be..0aac2182 100644 --- a/lib/Froxlor/Api/Commands/IpsAndPorts.php +++ b/lib/Froxlor/Api/Commands/IpsAndPorts.php @@ -65,7 +65,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin() && ($this->getUserDetail('change_serversettings') || !empty($this->getUserDetail('ip')))) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list ips and ports"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list ips and ports"); $ip_where = ""; $append_where = false; if (!empty($this->getUserDetail('ip')) && $this->getUserDetail('ip') != -1) { @@ -335,7 +335,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity 'id' => $id ], true, true); if ($result) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get ip " . $result['ip'] . " " . $result['port']); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get ip " . $result['ip'] . " " . $result['port']); return $this->response($result); } throw new Exception("IP/port with id #" . $id . " could not be found", 404); diff --git a/lib/Froxlor/Api/Commands/MysqlServer.php b/lib/Froxlor/Api/Commands/MysqlServer.php index c1fbbea2..a3f6a830 100644 --- a/lib/Froxlor/Api/Commands/MysqlServer.php +++ b/lib/Froxlor/Api/Commands/MysqlServer.php @@ -26,14 +26,15 @@ namespace Froxlor\Api\Commands; use Exception; -use PDO; -use PDOException; -use Froxlor\Froxlor; -use Froxlor\PhpHelper; use Froxlor\Api\ApiCommand; use Froxlor\Api\ResourceEntity; use Froxlor\Database\Database; +use Froxlor\Froxlor; +use Froxlor\FroxlorLogger; +use Froxlor\PhpHelper; use Froxlor\Validate\Validate; +use PDO; +use PDOException; class MysqlServer extends ApiCommand implements ResourceEntity { @@ -73,8 +74,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity * optional, test connection with given credentials, default is true (yes) * * @access admin - * @throws Exception * @return string json-encoded array + * @throws Exception */ public function add() { @@ -112,7 +113,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity ); if (!empty($mysql_ca)) { $options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca; - $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert; + $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert; } $dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";"; @@ -167,6 +168,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity $this->addDatabaseFromCustomerAllowedList($newdbserver); } + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added new database server '" . $description . "' (" . $mysql_host . ")"); + return $this->response(['dbserver' => $newdbserver]); } @@ -179,16 +182,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity * optional the number of the mysql server (either id or dbserver must be set) * * @access admin - * @throws Exception * @return string json-encoded array + * @throws Exception */ public function delete() { $this->validateAccess(); - $id = (int) $this->getParam('id', true, -1); + $id = (int)$this->getParam('id', true, -1); $dn_optional = $id >= 0; - $dbserver = (int) $this->getParam('dbserver', $dn_optional, -1); + $dbserver = (int)$this->getParam('dbserver', $dn_optional, -1); $dbserver = $id >= 0 ? $id : $dbserver; if ($dbserver == 0) { @@ -212,8 +215,12 @@ class MysqlServer extends ApiCommand implements ResourceEntity // when removing, remove from list of allowed_mysqlservers from any customers $this->removeDatabaseFromCustomerAllowedList($dbserver); + $description = $sql_root[$dbserver]['caption'] ?? "unknown"; + $mysql_host = $sql_root[$dbserver]['host'] ?? "unknown"; unset($sql_root[$dbserver]); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] removed database server '" . $description . "' (" . $mysql_host . ")"); + $this->generateNewUserData($sql, $sql_root); return $this->response(['true']); } @@ -287,14 +294,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity * optional the number of the mysql server (either id or dbserver must be set) * * @access admin, customer - * @throws Exception * @return string json-encoded array + * @throws Exception */ public function get() { - $id = (int) $this->getParam('id', true, -1); + $id = (int)$this->getParam('id', true, -1); $dn_optional = $id >= 0; - $dbserver = (int) $this->getParam('dbserver', $dn_optional, -1); + $dbserver = (int)$this->getParam('dbserver', $dn_optional, -1); $dbserver = $id >= 0 ? $id : $dbserver; $sql_root = []; @@ -317,6 +324,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity unset($sql_root[$dbserver]['password']); $sql_root[$dbserver]['id'] = $dbserver; + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get database-server '" . $sql_root[$dbserver]['caption'] . "'"); return $this->response($sql_root[$dbserver]); } @@ -347,16 +355,16 @@ class MysqlServer extends ApiCommand implements ResourceEntity * optional, test connection with given credentials, default is true (yes) * * @access admin - * @throws Exception * @return string json-encoded array + * @throws Exception */ public function update() { $this->validateAccess(); - $id = (int) $this->getParam('id', true, -1); + $id = (int)$this->getParam('id', true, -1); $dn_optional = $id >= 0; - $dbserver = (int) $this->getParam('dbserver', $dn_optional, -1); + $dbserver = (int)$this->getParam('dbserver', $dn_optional, -1); $dbserver = $id >= 0 ? $id : $dbserver; $sql_root = []; @@ -417,7 +425,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity ); if (!empty($mysql_ca)) { $options[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ca; - $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool) $mysql_verifycert; + $options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (bool)$mysql_verifycert; } $dsn = "mysql:host=" . $mysql_host . ";port=" . $mysql_port . ";"; @@ -448,6 +456,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity $this->addDatabaseFromCustomerAllowedList($dbserver); } + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] edited database server '" . $description . "' (" . $mysql_host . ")"); + return $this->response(['true']); } @@ -472,7 +482,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity WHERE `dbserver` = :dbserver "); $result = Database::pexecute_first($result_stmt, ['dbserver' => $dbserver], true, true); - return (int) $result['num_dbs']; + return (int)$result['num_dbs']; } else { $dbserver = $this->getParam('mysql_server'); $customer_ids = $this->getAllowedCustomerIds(); diff --git a/lib/Froxlor/Api/Commands/Mysqls.php b/lib/Froxlor/Api/Commands/Mysqls.php index c5d78501..8ef6c1e7 100644 --- a/lib/Froxlor/Api/Commands/Mysqls.php +++ b/lib/Froxlor/Api/Commands/Mysqls.php @@ -199,7 +199,7 @@ class Mysqls extends ApiCommand implements ResourceEntity $this->mailer()->clearAddresses(); } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] added mysql-database '" . $username . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added mysql-database '" . $username . "'"); $result = $this->apiCall('Mysqls.get', [ 'dbname' => $username, @@ -299,7 +299,7 @@ class Mysqls extends ApiCommand implements ResourceEntity $mbdata = $mbdata_stmt->fetch(PDO::FETCH_ASSOC); Database::needRoot(false); $result['size'] = $mbdata['MB'] ?? 0; - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get database '" . $result['databasename'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get database '" . $result['databasename'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "dbname '" . $dbname . "'"); @@ -388,7 +388,7 @@ class Mysqls extends ApiCommand implements ResourceEntity ]; Database::pexecute($stmt, $params, true, true); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] updated mysql-database '" . $result['databasename'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] updated mysql-database '" . $result['databasename'] . "'"); $result = $this->apiCall('Mysqls.get', [ 'dbname' => $result['databasename'] ]); diff --git a/lib/Froxlor/Api/Commands/PhpSettings.php b/lib/Froxlor/Api/Commands/PhpSettings.php index cb5c396b..588c04a6 100644 --- a/lib/Froxlor/Api/Commands/PhpSettings.php +++ b/lib/Froxlor/Api/Commands/PhpSettings.php @@ -67,7 +67,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity public function listing() { if ($this->isAdmin()) { - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list php-configs"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list php-configs"); $with_subdomains = $this->getBoolParam('with_subdomains', true, false); $query_fields = []; @@ -392,7 +392,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity $ins_data['id'] = Database::lastInsertId(); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'"); $result = $this->apiCall('PhpSettings.get', [ 'id' => $ins_data['id'] @@ -629,7 +629,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity Database::pexecute($upd_stmt, $upd_data, true, true); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'"); $result = $this->apiCall('PhpSettings.get', [ 'id' => $id @@ -686,7 +686,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity ], true, true); Cronjob::inserttask(TaskId::REBUILD_VHOST); - $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'"); + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'"); return $this->response($result); } throw new Exception("Not allowed to execute given command.", 403); diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index 433871f0..ed8f49fc 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -486,7 +486,7 @@ class SubDomains extends ApiCommand implements ResourceEntity $result['ipsandports'] = $this->getIpsForDomain($result['id']); } $result['domain_hascert'] = $this->getHasCertValueForDomain((int)$result['id'], (int)$result['parentdomainid']); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get subdomain '" . $result['domain'] . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get subdomain '" . $result['domain'] . "'"); return $this->response($result); } $key = ($id > 0 ? "id #" . $id : "domainname '" . $domainname . "'"); @@ -856,7 +856,7 @@ class SubDomains extends ApiCommand implements ResourceEntity Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::REBUILD_DNS); $idna_convert = new IdnaWrapper(); - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'"); } $result = $this->apiCall('SubDomains.get', [ 'id' => $id diff --git a/lib/Froxlor/Api/Commands/SysLog.php b/lib/Froxlor/Api/Commands/SysLog.php index c3686a54..9236d577 100644 --- a/lib/Froxlor/Api/Commands/SysLog.php +++ b/lib/Froxlor/Api/Commands/SysLog.php @@ -92,7 +92,7 @@ class SysLog extends ApiCommand implements ResourceEntity while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list log-entries"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries"); return $this->response([ 'count' => count($result), 'list' => $result diff --git a/lib/Froxlor/Api/Commands/Traffic.php b/lib/Froxlor/Api/Commands/Traffic.php index dc657133..1f8692b9 100644 --- a/lib/Froxlor/Api/Commands/Traffic.php +++ b/lib/Froxlor/Api/Commands/Traffic.php @@ -166,7 +166,7 @@ class Traffic extends ApiCommand implements ResourceEntity $row['mail'] *= 1024; $result[] = $row; } - $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] list traffic"); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list traffic"); return $this->response([ 'count' => count($result), 'list' => $result From 981d819fd727318326e38a019292f65ce1c63c2d Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 09:05:49 +0200 Subject: [PATCH 21/26] display notice if customer has no domains assigned yet to add subdomains; corrected subdomains-usage-check to exclude std-subdomain Signed-off-by: Michael Kaufmann --- customer_domains.php | 21 ++++++++++++++++++--- customer_email.php | 2 +- lib/Froxlor/Api/ApiCommand.php | 3 ++- lib/Froxlor/Cron/Http/Php/Fpm.php | 2 +- lib/Froxlor/CurrentUser.php | 20 +++++++++++++------- lng/de.lng.php | 1 + lng/en.lng.php | 1 + templates/Froxlor/user/table.html.twig | 2 +- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/customer_domains.php b/customer_domains.php index 933edd13..45348e2f 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -51,7 +51,7 @@ $id = (int)Request::any('id'); if ($page == 'overview' || $page == 'domains') { if ($action == '') { - $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_domains::domains"); + $log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_domains::domains"); $parentdomain_id = (int)Request::any('pid', '0'); @@ -73,10 +73,17 @@ if ($page == 'overview' || $page == 'domains') { ]; } - UI::view('user/table.html.twig', [ + $table_tpl = 'table.html.twig'; + if ($collection->count() == 0) { + $table_tpl = 'table-note.html.twig'; + } + UI::view('user/' . $table_tpl, [ 'listing' => Listing::format($collection, $domain_list_data, 'domain_list'), 'actions_links' => $actions_links, - 'entity_info' => lng('domains.description') + 'entity_info' => lng('domains.description'), + // alert-box + 'type' => 'warning', + 'alert_msg' => lng('domains.nodomainsassignedbyadmin') ]); } elseif ($action == 'delete' && $id != 0) { try { @@ -139,6 +146,14 @@ if ($page == 'overview' || $page == 'domains') { $domains[$row['domain']] = $idna_convert->decode($row['domain']); } + // check of there are any domains to be used + if (count($domains) <= 0) { + // no, possible direct URL access, redirect to overview + Response::redirectTo($filename, [ + 'page' => $page + ]); + } + $aliasdomains[0] = lng('domains.noaliasdomain'); $domains_stmt = Database::prepare("SELECT `d`.`id`, `d`.`domain` FROM `" . TABLE_PANEL_DOMAINS . "` `d`, `" . TABLE_PANEL_CUSTOMERS . "` `c` WHERE `d`.`aliasdomain` IS NULL diff --git a/customer_email.php b/customer_email.php index a9944734..ca311caa 100644 --- a/customer_email.php +++ b/customer_email.php @@ -84,7 +84,7 @@ if ($page == 'overview' || $page == 'emails') { if ($page == 'email_domain') { $email_domainid = Request::any('domainid', 0); if ($action == '') { - $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_email::emails"); + $log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_email::emails"); $sql_search = []; if ($email_domainid > 0) { diff --git a/lib/Froxlor/Api/ApiCommand.php b/lib/Froxlor/Api/ApiCommand.php index 210d28ac..327a1b4d 100644 --- a/lib/Froxlor/Api/ApiCommand.php +++ b/lib/Froxlor/Api/ApiCommand.php @@ -272,7 +272,8 @@ abstract class ApiCommand extends ApiParameter $ops = [ '<', '>', - '=' + '=', + '<>' ]; $first = true; foreach ($search as $field => $valoper) { diff --git a/lib/Froxlor/Cron/Http/Php/Fpm.php b/lib/Froxlor/Cron/Http/Php/Fpm.php index 1cf84901..3c96fe1b 100644 --- a/lib/Froxlor/Cron/Http/Php/Fpm.php +++ b/lib/Froxlor/Cron/Http/Php/Fpm.php @@ -289,7 +289,7 @@ pm.max_children = 1 } } - // now check if 'sendmail_path' has not beed set in the custom-php.ini + // now check if 'sendmail_path' has not been set in the custom-php.ini // if not we use our fallback-default as usual if (strpos($fpm_config, 'php_admin_value[sendmail_path]') === false) { $fpm_config .= 'php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f ' . $this->domain['email'] . "\n"; diff --git a/lib/Froxlor/CurrentUser.php b/lib/Froxlor/CurrentUser.php index 22a62082..6c814b47 100644 --- a/lib/Froxlor/CurrentUser.php +++ b/lib/Froxlor/CurrentUser.php @@ -25,10 +25,10 @@ namespace Froxlor; -use Froxlor\Database\Database; -use Froxlor\UI\Collection; use Froxlor\Api\Commands\Customers; use Froxlor\Api\Commands\SubDomains; +use Froxlor\Database\Database; +use Froxlor\UI\Collection; /** * Class to manage the current user / session @@ -151,15 +151,21 @@ class CurrentUser ]); $addition = $result['emaildomains'] != 0; } elseif ($resource == 'subdomains') { - $parentDomainCollection = (new Collection(SubDomains::class, $_SESSION['userinfo'], - ['sql_search' => ['d.parentdomainid' => 0]])); - $addition = $parentDomainCollection != 0; + $parentDomainCollection = (new Collection( + SubDomains::class, + $_SESSION['userinfo'], + ['sql_search' => [ + 'd.parentdomainid' => 0, + 'd.id' => ['op' => '<>', 'value' => $_SESSION['userinfo']['standardsubdomain']] + ] + ] + )); + $addition = $parentDomainCollection->count() != 0; } elseif ($resource == 'domains') { $customerCollection = (new Collection(Customers::class, $_SESSION['userinfo'])); - $addition = $customerCollection != 0; + $addition = $customerCollection->count() != 0; } return ($_SESSION['userinfo'][$resource . '_used'] < $_SESSION['userinfo'][$resource] || $_SESSION['userinfo'][$resource] == '-1') && $addition; } - } diff --git a/lng/de.lng.php b/lng/de.lng.php index 616f92aa..0c6e3353 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -699,6 +699,7 @@ return [ 'openbasedirenabled' => 'Openbasedir Einschränkung', 'hsts' => 'HSTS aktiviert', 'aliasdomainid' => 'ID der Alias-Domain', + 'nodomainsassignedbyadmin' => 'Diesem Account wurde noch keine Domain zugewiesen. Bitte kontaktiere deinen Administrator, wenn du der Meinung bist, das ist nicht korrekt.', ], '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', diff --git a/lng/en.lng.php b/lng/en.lng.php index 45925fc2..51f8f784 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -765,6 +765,7 @@ return [ 'openbasedirenabled' => 'Openbasedir restiction', 'hsts' => 'HSTS enabled', 'aliasdomainid' => 'ID of alias domain', + 'nodomainsassignedbyadmin' => 'Your account has currently no domains assigned to it. Please contact your administrator if you think this is wrong.', ], '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', diff --git a/templates/Froxlor/user/table.html.twig b/templates/Froxlor/user/table.html.twig index 5ca36e4f..fac9e0d6 100644 --- a/templates/Froxlor/user/table.html.twig +++ b/templates/Froxlor/user/table.html.twig @@ -35,7 +35,7 @@ {% for link in actions_links %} - {{ link.label }} + {% if link.label is defined and link.label is not empty %}{{ link.label }}{% endif %} {% endfor %} {% endif %} From 20755bceadd8b20db613037f87c12748487ec971 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 09:35:12 +0200 Subject: [PATCH 22/26] set version in 2.1.x branch to 2.1.0-alpha1 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Froxlor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 935b1092..0c2fa9ee 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -31,7 +31,7 @@ final class Froxlor { // Main version variable - const VERSION = '2.0.20'; + const VERSION = '2.1.0-alpha1'; // Database version (YYYYMMDDC where C is a daily counter) const DBVERSION = '202305240'; From 9ed45ea7f8c7fef33a832211dfd0e2d0d04413b4 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 09:46:31 +0200 Subject: [PATCH 23/26] make alpha to dev, version check does not know about 'alpha' Signed-off-by: Michael Kaufmann --- lib/Froxlor/Froxlor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 0c2fa9ee..549908e4 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -31,7 +31,7 @@ final class Froxlor { // Main version variable - const VERSION = '2.1.0-alpha1'; + const VERSION = '2.1.0-dev1'; // Database version (YYYYMMDDC where C is a daily counter) const DBVERSION = '202305240'; From 196ef9378a6c9f450f0e33563ff73c029f6c29f1 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 10:10:32 +0200 Subject: [PATCH 24/26] deactivate/reactivate email-accounts for deactivated/reactivated domain; set deactivated-docroot by default to not have deactivated domains point to froxlor login but rather show a message Signed-off-by: Michael Kaufmann --- .gitignore | 1 + install/froxlor.sql.php | 2 +- install/updates/froxlor/update_2.x.inc.php | 9 ++++ lib/Froxlor/Api/Commands/Domains.php | 21 +++++++- lib/Froxlor/Install/Install/Core.php | 1 + templates/misc/deactivated/index.html | 56 ++++++++++++++++++++++ 6 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 templates/misc/deactivated/index.html diff --git a/.gitignore b/.gitignore index bbad0ca0..a9416c61 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ logs/* *~ .well-known .idea +.DS_Store *.iml img/ vendor/ diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 82f49de8..0e06cbe3 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -554,7 +554,7 @@ opcache.validate_timestamps'), ('system', 'defaultip', '1'), ('system', 'defaultsslip', ''), ('system', 'phpappendopenbasedir', '/tmp/'), - ('system', 'deactivateddocroot', ''), + ('system', 'deactivateddocroot', '/var/www/html/froxlor/templates/misc/deactivated/'), ('system', 'mailpwcleartext', '0'), ('system', 'last_tasks_run', '000000'), ('system', 'nameservers', ''), diff --git a/install/updates/froxlor/update_2.x.inc.php b/install/updates/froxlor/update_2.x.inc.php index bd443a0d..83906fb0 100644 --- a/install/updates/froxlor/update_2.x.inc.php +++ b/install/updates/froxlor/update_2.x.inc.php @@ -515,5 +515,14 @@ if (Froxlor::isDatabaseVersion('202304260')) { Database::query($sql); Update::lastStepStatus(0); + Update::showUpdateStep("Adjusting setting for deactivated webroot"); + $current_deactivated_webroot = Settings::Get('system.deactivateddocroot'); + if (empty($current_deactivated_webroot)) { + Settings::Set('system.deactivateddocroot', FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/templates/misc/deactivated/')); + Update::lastStepStatus(0); + } else { + Update::lastStepStatus(1, 'Customized setting, not changing'); + } + Froxlor::updateToDbVersion('202305240'); } diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 7fb7991c..d16030e1 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1890,7 +1890,26 @@ class Domains extends ApiCommand implements ResourceEntity // activate/deactivate domain-based services if ($deactivated != $result['deactivated']) { - // @TODO + // deactivate email accounts + $yesno = ($deactivated ? 'N' : 'Y'); + $pop3 = ($deactivated ? '0' : (int)$result['pop3']); + $imap = ($deactivated ? '0' : (int)$result['imap']); + + $upd_stmt = Database::prepare(" + UPDATE `" . TABLE_MAIL_USERS . "` + SET `postfix`= :yesno, `pop3` = :pop3, `imap` = :imap + WHERE `customerid` = :customerid AND `domainid` = :domainid + "); + Database::pexecute($upd_stmt, [ + 'yesno' => $yesno, + 'pop3' => $pop3, + 'imap' => $imap, + 'customerid' => $customerid, + 'domainid' => $id + ]); + + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " domain '" . $result['domain'] . "'"); + Cronjob::inserttask(TaskId::REBUILD_VHOST); } $_update_data['customerid'] = $customerid; diff --git a/lib/Froxlor/Install/Install/Core.php b/lib/Froxlor/Install/Install/Core.php index 3ba10023..5eb04f9a 100644 --- a/lib/Froxlor/Install/Install/Core.php +++ b/lib/Froxlor/Install/Install/Core.php @@ -421,6 +421,7 @@ class Core $this->updateSetting($upd_stmt, $this->validatedData['activate_newsfeed'], 'admin', 'show_news_feed'); $this->updateSetting($upd_stmt, dirname(__FILE__, 5), 'system', 'letsencryptchallengepath'); + $this->updateSetting($upd_stmt, dirname(__FILE__, 5) . '/templates/misc/deactivated/', 'system', 'deactivateddocroot'); // insert the lastcronrun to be the installation date $this->updateSetting($upd_stmt, time(), 'system', 'lastcronrun'); diff --git a/templates/misc/deactivated/index.html b/templates/misc/deactivated/index.html new file mode 100644 index 00000000..a07df96f --- /dev/null +++ b/templates/misc/deactivated/index.html @@ -0,0 +1,56 @@ + + + + + + + froxlor - Deactivated page + + + +
+

Domain deactivated

+

+ This domain is managed using the froxlor Server Management Panel. + If you see this page, this domain has been deactivated by an administrator. +

+
    +
  • + + + + Please ask your provider/hoster if you think this is not correct +
  • +
+
+ + + + From 6e37b55ac619d6dbe71f9ddfdc62c55afaf4c117 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 10:23:47 +0200 Subject: [PATCH 25/26] more integration of domain deactivated flag Signed-off-by: Michael Kaufmann --- customer_domains.php | 1 + lib/Froxlor/Api/Commands/Emails.php | 5 ++++- lib/Froxlor/Api/Commands/SubDomains.php | 3 +++ lib/Froxlor/CurrentUser.php | 3 ++- lng/de.lng.php | 3 ++- lng/en.lng.php | 3 ++- 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/customer_domains.php b/customer_domains.php index 45348e2f..2fba8e38 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -137,6 +137,7 @@ if ($page == 'overview' || $page == 'domains') { AND `parentdomainid` = '0' AND `email_only` = '0' AND `caneditdomain` = '1' + AND `deactivated` = '0' ORDER BY `domain` ASC"); Database::pexecute($stmt, [ "customerid" => $userinfo['customerid'] diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 221efa9b..85c19a49 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -88,9 +88,12 @@ class Emails extends ApiCommand implements ResourceEntity $domain_check = $this->apiCall('SubDomains.get', [ 'domainname' => $domain ], true); - if ($domain_check['isemaildomain'] == 0) { + if ((int)$domain_check['isemaildomain'] == 0) { Response::standardError('maindomainnonexist', $domain, true); } + if ((int)$domain_check['deactivated'] == 1) { + Response::standardError('maindomaindeactivated', $domain, true); + } if (Settings::Get('catchall.catchall_enabled') != '1') { $iscatchall = 0; diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index fdc6e9c8..77cf0377 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -229,6 +229,9 @@ class SubDomains extends ApiCommand implements ResourceEntity } elseif ($completedomain_check && strtolower($completedomain_check['domain']) == strtolower($completedomain)) { // the domain does already exist as main-domain Response::standardError('domainexistalready', $completedomain, true); + } elseif ((int)$domain_check['deactivated'] == 1) { + // main domain is deactivated + Response::standardError('maindomaindeactivated', $domain, true); } // if allowed, check for 'is email domain'-flag diff --git a/lib/Froxlor/CurrentUser.php b/lib/Froxlor/CurrentUser.php index 6c814b47..45168176 100644 --- a/lib/Froxlor/CurrentUser.php +++ b/lib/Froxlor/CurrentUser.php @@ -144,7 +144,7 @@ class CurrentUser $result_stmt = Database::prepare(" SELECT COUNT(`id`) as emaildomains FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE `customerid`= :cid AND `isemaildomain` = '1' + WHERE `customerid`= :cid AND `isemaildomain` = '1' AND `deactivated` = '0' "); $result = Database::pexecute_first($result_stmt, [ "cid" => $_SESSION['userinfo']['customerid'] @@ -156,6 +156,7 @@ class CurrentUser $_SESSION['userinfo'], ['sql_search' => [ 'd.parentdomainid' => 0, + 'd.deactivated' => 0, 'd.id' => ['op' => '<>', 'value' => $_SESSION['userinfo']['standardsubdomain']] ] ] diff --git a/lng/de.lng.php b/lng/de.lng.php index 0c6e3353..c02a5e2b 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -699,7 +699,7 @@ return [ 'openbasedirenabled' => 'Openbasedir Einschränkung', 'hsts' => 'HSTS aktiviert', 'aliasdomainid' => 'ID der Alias-Domain', - 'nodomainsassignedbyadmin' => 'Diesem Account wurde noch keine Domain zugewiesen. Bitte kontaktiere deinen Administrator, wenn du der Meinung bist, das ist nicht korrekt.', + 'nodomainsassignedbyadmin' => 'Diesem Account wurde noch keine (aktive) Domain zugewiesen. Bitte kontaktiere deinen Administrator, wenn du der Meinung bist, das ist nicht korrekt.', ], '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', @@ -770,6 +770,7 @@ return [ 'domainisaliasorothercustomer' => 'Die ausgewählte Aliasdomain ist entweder selbst eine Aliasdomain, hat nicht die gleiche IP/Port-Kombination oder gehört einem anderen Kunden.', 'emailexistalready' => 'Die E-Mail-Adresse "%s" existiert bereits.', 'maindomainnonexist' => 'Die Hauptdomain "%s" existiert nicht.', + 'maindomaindeactivated' => 'Die Hauptdomain "%s" ist deaktiviert.', 'destinationnonexist' => 'Bitte geben Sie Ihre Weiterleitungsadresse im Feld \'Nach\' ein.', 'destinationalreadyexistasmail' => 'Die Weiterleitung zu "%s" existiert bereits als aktive E-Mail-Adresse.', 'destinationalreadyexist' => 'Es existiert bereits eine Weiterleitung nach "%s".', diff --git a/lng/en.lng.php b/lng/en.lng.php index 51f8f784..234a8ca6 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -765,7 +765,7 @@ return [ 'openbasedirenabled' => 'Openbasedir restiction', 'hsts' => 'HSTS enabled', 'aliasdomainid' => 'ID of alias domain', - 'nodomainsassignedbyadmin' => 'Your account has currently no domains assigned to it. Please contact your administrator if you think this is wrong.', + 'nodomainsassignedbyadmin' => 'Your account has currently no (active) domains assigned to it. Please contact your administrator if you think this is wrong.', ], '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', @@ -836,6 +836,7 @@ return [ 'domainisaliasorothercustomer' => 'The selected alias domain is either itself an alias domain, has a different ip/port combination or belongs to another customer.', 'emailexistalready' => 'The email-address %s already exists.', 'maindomainnonexist' => 'The main-domain %s does not exist.', + 'maindomaindeactivated' => 'The main-domain %s is deactivated.', 'destinationnonexist' => 'Please create your forwarder in the field \'Destination\'.', 'destinationalreadyexistasmail' => 'The forwarder to %s already exists as active email-address.', 'destinationalreadyexist' => 'You have already defined a forwarder to "%s"', From 03257f04cba9c12f787ee7816044da3aa7708556 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 6 Jun 2023 14:10:07 +0200 Subject: [PATCH 26/26] more integration of domain deactivated flag Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Domains.php | 4 ++-- lib/Froxlor/Api/Commands/EmailAccounts.php | 4 ++++ lib/Froxlor/UI/Callbacks/Style.php | 6 +++--- lib/navigation/00.froxlor.main.php | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index d16030e1..e916c072 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1892,8 +1892,8 @@ class Domains extends ApiCommand implements ResourceEntity if ($deactivated != $result['deactivated']) { // deactivate email accounts $yesno = ($deactivated ? 'N' : 'Y'); - $pop3 = ($deactivated ? '0' : (int)$result['pop3']); - $imap = ($deactivated ? '0' : (int)$result['imap']); + $pop3 = ($deactivated ? '0' : (int)$customer['pop3']); + $imap = ($deactivated ? '0' : (int)$customer['imap']); $upd_stmt = Database::prepare(" UPDATE `" . TABLE_MAIL_USERS . "` diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index 605a6daa..e560fd0d 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -95,9 +95,13 @@ class EmailAccounts extends ApiCommand implements ResourceEntity $customer = $this->getCustomerData('email_accounts'); // check for imap||pop3 == 1, see #1298 + // d00p, 6.5.2023 @revert this - if a customer has resources which allow email accounts + // it implicitly allowed SMTP, e.g. sending of emails which also requires an account to exist + /* if ($customer['imap'] != '1' && $customer['pop3'] != '1') { Response::standardError('notallowedtouseaccounts', '', true); } + */ if (!empty($emailaddr)) { $idna_convert = new IdnaWrapper(); diff --git a/lib/Froxlor/UI/Callbacks/Style.php b/lib/Froxlor/UI/Callbacks/Style.php index 6f19bee8..1019151c 100644 --- a/lib/Froxlor/UI/Callbacks/Style.php +++ b/lib/Froxlor/UI/Callbacks/Style.php @@ -60,18 +60,18 @@ class Style $today = time(); $termination_css = 'bg-warning'; if ($cdate < $today) { - $termination_css = 'bg-danger'; + $termination_css = 'bg-danger text-light'; } } $deactivated = $attributes['fields']['deactivated'] || $attributes['fields']['customer_deactivated']; - return $deactivated ? 'bg-info' : $termination_css; + return $deactivated ? 'bg-info text-light' : $termination_css; } public static function resultCustomerLockedOrDeactivated(array $attributes): string { $row_css = ''; if ((int)$attributes['fields']['deactivated'] == 1) { - $row_css = 'bg-info'; + $row_css = 'bg-info text-light'; } elseif ( $attributes['fields']['loginfail_count'] >= Settings::Get('login.maxloginattempts') && $attributes['fields']['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime')) diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index d65819fb..45568057 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -186,7 +186,7 @@ return [ 'url' => 'admin_customers.php?page=customers', 'label' => lng('admin.customers'), 'required_resources' => 'customers', - 'add_shortlink' => CurrentUser::canAddResource('customers') ? 'admin_customers.php?page=customers&action=add' : null, + 'add_shortlink' => CurrentUser::isAdmin() && CurrentUser::canAddResource('customers') ? 'admin_customers.php?page=customers&action=add' : null, ], [ 'url' => 'admin_admins.php?page=admins', @@ -198,7 +198,7 @@ return [ 'url' => 'admin_domains.php?page=domains', 'label' => lng('admin.domains'), 'required_resources' => 'domains', - 'add_shortlink' => CurrentUser::canAddResource('domains') ? 'admin_domains.php?page=domains&action=add' : null, + 'add_shortlink' => CurrentUser::isAdmin() && CurrentUser::canAddResource('domains') ? 'admin_domains.php?page=domains&action=add' : null, ], [ 'url' => 'admin_domains.php?page=sslcertificates',