From 13aa07ed1a35a6f550e14dd5591b1196ed6dff16 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 20 Nov 2024 16:53:28 +0100 Subject: [PATCH 01/19] add new settings to set default values for customer antispam options for new email addresses (settings advanced-mode) Signed-off-by: Michael Kaufmann --- actions/admin/settings/180.antispam.php | 45 +++++++++++++++++ install/froxlor.sql.php | 5 +- install/updates/froxlor/update_2.2.inc.php | 11 ++++ lib/Froxlor/Api/Commands/Emails.php | 50 ++++++++++++++----- lib/Froxlor/Froxlor.php | 2 +- .../customer/email/formfield.emails_edit.php | 6 +-- lng/de.lng.php | 18 +++++++ lng/en.lng.php | 18 +++++++ 8 files changed, 138 insertions(+), 17 deletions(-) diff --git a/actions/admin/settings/180.antispam.php b/actions/admin/settings/180.antispam.php index 01990c53..b599a443 100644 --- a/actions/admin/settings/180.antispam.php +++ b/actions/admin/settings/180.antispam.php @@ -58,6 +58,51 @@ return [ 'save_method' => 'storeSettingField', 'required_otp' => true ], + 'antispam_default_bypass_spam' => [ + 'label' => lng('antispam.default_bypass_spam'), + 'settinggroup' => 'antispam', + 'varname' => 'default_bypass_spam', + 'type' => 'select', + 'default' => 2, + 'select_var' => [ + 1 => lng('antispam.default_select.on_changeable'), + 2 => lng('antispam.default_select.off_changeable'), + 3 => lng('antispam.default_select.on_unchangeable'), + 4 => lng('antispam.default_select.off_unchangeable'), + ], + 'save_method' => 'storeSettingField', + 'advanced_mode' => true + ], + 'antispam_default_spam_rewrite_subject' => [ + 'label' => lng('antispam.default_spam_rewrite_subject'), + 'settinggroup' => 'antispam', + 'varname' => 'default_spam_rewrite_subject', + 'type' => 'select', + 'default' => 1, + 'select_var' => [ + 1 => lng('antispam.default_select.on_changeable'), + 2 => lng('antispam.default_select.off_changeable'), + 3 => lng('antispam.default_select.on_unchangeable'), + 4 => lng('antispam.default_select.off_unchangeable'), + ], + 'save_method' => 'storeSettingField', + 'advanced_mode' => true + ], + 'antispam_default_policy_greylist' => [ + 'label' => lng('antispam.default_policy_greylist'), + 'settinggroup' => 'antispam', + 'varname' => 'default_policy_greylist', + 'type' => 'select', + 'default' => 1, + 'select_var' => [ + 1 => lng('antispam.default_select.on_changeable'), + 2 => lng('antispam.default_select.off_changeable'), + 3 => lng('antispam.default_select.on_unchangeable'), + 4 => lng('antispam.default_select.off_unchangeable'), + ], + 'save_method' => 'storeSettingField', + 'advanced_mode' => true + ], 'antispam_dkim_keylength' => [ 'label' => lng('antispam.dkim_keylength'), 'settinggroup' => 'antispam', diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 1bdd3b67..53d7be99 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -391,6 +391,9 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('antispam', 'config_file', '/etc/rspamd/local.d/froxlor_settings.conf'), ('antispam', 'reload_command', 'service rspamd restart'), ('antispam', 'dkim_keylength', '1024'), + ('antispam', 'default_bypass_spam', '2'), + ('antispam', 'default_spam_rewrite_subject', '1'), + ('antispam', 'default_policy_greylist', '1'), ('admin', 'show_news_feed', '0'), ('admin', 'show_version_login', '0'), ('admin', 'show_version_footer', '0'), @@ -731,7 +734,7 @@ opcache.validate_timestamps'), ('panel', 'settings_mode', '0'), ('panel', 'menu_collapsed', '1'), ('panel', 'version', '2.2.5'), - ('panel', 'db_version', '202409280'); + ('panel', 'db_version', '202411200'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index 0248c7f6..4efaf797 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -198,3 +198,14 @@ if (Froxlor::isFroxlorVersion('2.2.4')) { Update::showUpdateStep("Updating from 2.2.4 to 2.2.5", false); Froxlor::updateToVersion('2.2.5'); } + +if (Froxlor::isDatabaseVersion('202409280')) { + + Update::showUpdateStep("Adding new antispam settings"); + Settings::AddNew("antispam.default_bypass_spam", "2"); + Settings::AddNew("antispam.default_spam_rewrite_subject", "1"); + Settings::AddNew("antispam.default_policy_greylist", "1"); + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202411200'); +} diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 5294e639..d68bf1a5 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -54,13 +54,13 @@ class Emails extends ApiCommand implements ResourceEntity * @param float $spam_tag_level * optional, score which is required to tag emails as spam, default: 7.0 * @param bool $rewrite_subject - * optional, whether to add ***SPAM*** to the email's subject if applicable, default true + * optional, whether to add ***SPAM*** to the email's subject if applicable, default: [antispam.default_spam_rewrite_subject] * @param float $spam_kill_level * optional, score which is required to discard emails, default: 14.0 * @param boolean $bypass_spam - * optional, disable spam-filter entirely, default: no + * optional, disable spam-filter entirely, default: [antispam.default_bypass_spam] * @param boolean $policy_greylist - * optional, enable grey-listing, default: yes + * optional, enable grey-listing, default: [antispam.default_policy_greylist] * @param boolean $iscatchall * optional, make this address a catchall address, default: no * @param int $customerid @@ -87,13 +87,26 @@ class Emails extends ApiCommand implements ResourceEntity // parameters $spam_tag_level = $this->getParam('spam_tag_level', true, '7.0'); - $rewrite_subject = $this->getBoolParam('rewrite_subject', true, 1); $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, '14.0'); - $bypass_spam = $this->getBoolParam('bypass_spam', true, 0); - $policy_greylist = $this->getBoolParam('policy_greylist', true, 1); $iscatchall = $this->getBoolParam('iscatchall', true, 0); $description = $this->getParam('description', true, ''); + if ((int)Settings::Get('antispam.default_spam_rewrite_subject') <= 2) { + $rewrite_subject = $this->getBoolParam('rewrite_subject', true, (int)Settings::Get('antispam.default_spam_rewrite_subject') == 1 ? 1 : 0); + } else { + $rewrite_subject = (int)Settings::Get('antispam.default_spam_rewrite_subject') == 3 ? 1 : 0; + } + if ((int)Settings::Get('antispam.default_bypass_spam') <= 2) { + $bypass_spam = $this->getBoolParam('bypass_spam', true, (int)Settings::Get('antispam.default_bypass_spam') == 1 ? 1 : 0); + } else { + $bypass_spam = (int)Settings::Get('antispam.default_bypass_spam') == 3 ? 1 : 0; + } + if ((int)Settings::Get('antispam.default_policy_greylist') <= 2) { + $policy_greylist = $this->getBoolParam('policy_greylist', true, (int)Settings::Get('antispam.default_policy_greylist') == 1 ? 1 : 0); + } else { + $policy_greylist = (int)Settings::Get('antispam.default_policy_greylist') == 3 ? 1 : 0; + } + // validation $idna_convert = new IdnaWrapper(); if (substr($domain, 0, 4) != 'xn--') { @@ -258,13 +271,13 @@ class Emails extends ApiCommand implements ResourceEntity * @param float $spam_tag_level * optional, score which is required to tag emails as spam, default: 7.0 * @param bool $rewrite_subject - * optional, whether to add ***SPAM*** to the email's subject if applicable, default true + * optional, whether to add ***SPAM*** to the email's subject if applicable, default: [antispam.default_spam_rewrite_subject] * @param float $spam_kill_level * optional, score which is required to discard emails, default: 14.0 * @param boolean $bypass_spam - * optional, disable spam-filter entirely, default: no + * optional, disable spam-filter entirely, default: [antispam.default_bypass_spam] * @param boolean $policy_greylist - * optional, enable grey-listing, default: yes + * optional, enable grey-listing, default: [antispam.default_policy_greylist] * @param boolean $iscatchall * optional * @param string $description @@ -292,13 +305,26 @@ class Emails extends ApiCommand implements ResourceEntity // parameters $spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']); - $rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']); $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, $result['spam_kill_level']); - $bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']); - $policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']); $iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']); $description = $this->getParam('description', true, $result['description']); + if ((int)Settings::Get('antispam.default_spam_rewrite_subject') <= 2) { + $rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']); + } else { + $rewrite_subject = (int)Settings::Get('antispam.default_spam_rewrite_subject') == 3 ? 1 : 0; + } + if ((int)Settings::Get('antispam.default_bypass_spam') <= 2) { + $bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']); + } else { + $bypass_spam = (int)Settings::Get('antispam.default_bypass_spam') == 3 ? 1 : 0; + } + if ((int)Settings::Get('antispam.default_policy_greylist') <= 2) { + $policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']); + } else { + $policy_greylist = (int)Settings::Get('antispam.default_policy_greylist') == 3 ? 1 : 0; + } + // if enabling catchall is not allowed by settings, we do not need // to run update() if ($iscatchall && $result['iscatchall'] == 0 && Settings::Get('catchall.catchall_enabled') != '1') { diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 016bb0de..dadd7cae 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -34,7 +34,7 @@ final class Froxlor const VERSION = '2.2.5'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202409280'; + const DBVERSION = '202411200'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/formfields/customer/email/formfield.emails_edit.php b/lib/formfields/customer/email/formfield.emails_edit.php index 925acb1a..89f794d2 100644 --- a/lib/formfields/customer/email/formfield.emails_edit.php +++ b/lib/formfields/customer/email/formfield.emails_edit.php @@ -97,7 +97,7 @@ return [ 'checked' => (int)$result['iscatchall'], ], 'bypass_spam' => [ - 'visible' => Settings::Get('antispam.activated') == '1', + 'visible' => Settings::Get('antispam.activated') == '1' && (int)Settings::Get('antispam.default_bypass_spam') <= 2, 'label' => lng('antispam.bypass_spam'), 'type' => 'checkbox', 'value' => '1', @@ -112,7 +112,7 @@ return [ 'value' => $result['spam_tag_level'], ], 'spam_rewrite_subject' => [ - 'visible' => Settings::Get('antispam.activated') == '1', + 'visible' => Settings::Get('antispam.activated') == '1' && (int)Settings::Get('antispam.default_spam_rewrite_subject') <= 2, 'label' => lng('antispam.rewrite_subject'), 'type' => 'checkbox', 'value' => '1', @@ -127,7 +127,7 @@ return [ 'value' => $result['spam_kill_level'] ], 'policy_greylist' => [ - 'visible' => Settings::Get('antispam.activated') == '1', + 'visible' => Settings::Get('antispam.activated') == '1' && (int)Settings::Get('antispam.default_policy_greylist') <= 2, 'label' => lng('antispam.policy_greylist'), 'type' => 'checkbox', 'value' => '1', diff --git a/lng/de.lng.php b/lng/de.lng.php index 7199ee87..d10d72aa 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -640,6 +640,24 @@ return [ 'required_spf_dns' => 'Erforderlicher SPF DNS Eintrag', 'required_dmarc_dns' => 'Erforderlicher DMARC DNS Eintrag', 'required_dkim_dns' => 'Erforderlicher DKIM DNS Eintrag', + 'default_select' => [ + 'on_changeable' => 'Aktiviert, einstellbar', + 'off_changeable' => 'Deaktiviert, einstellbar', + 'on_unchangeable' => 'Aktiviert, nicht einstellbar', + 'off_unchangeable' => 'Deaktiviert, nicht einstellbar', + ], + 'default_bypass_spam' => [ + 'title' => 'Standardwert: Spamfilter umgehen', + 'description' => 'Wählen, ob bei neuen E-Mail-Konten "Spamfilter umgehen" standardmäßig aktiviert ist und ob diese Einstellung vom Kunden angepasst werden kann.
Standard: Deaktiviert, einstellbar' + ], + 'default_spam_rewrite_subject' => [ + 'title' => 'Standardwert: Betreff ändern', + 'description' => 'Wählen, ob bei neuen E-Mail-Konten "Betreff ändern" standardmäßig aktiviert ist und ob diese Einstellung vom Kunden angepasst werden kann.
Standard: Aktiviert, einstellbar' + ], + 'default_policy_greylist' => [ + 'title' => 'Standardwert: Verwende greylisting', + 'description' => 'Wählen, ob bei neuen E-Mail-Konten "Verwende greylisting" standardmäßig aktiviert ist und ob diese Einstellung vom Kunden angepasst werden kann.
Standard: Aktiviert, einstellbar' + ], ], 'dns' => [ 'destinationip' => 'Domain-IP-Adresse(n)', diff --git a/lng/en.lng.php b/lng/en.lng.php index 6c0af9c1..4ae337f4 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -689,6 +689,24 @@ return [ 'required_spf_dns' => 'Required SPF DNS entry', 'required_dmarc_dns' => 'Required DMARC DNS entry', 'required_dkim_dns' => 'Required DKIM DNS entry', + 'default_select' => [ + 'on_changeable' => 'Activated, adjustable', + 'off_changeable' => 'Deactivated, adjustable', + 'on_unchangeable' => 'Activated, not adjustable', + 'off_unchangeable' => 'Deactivated, not adjustable', + ], + 'default_bypass_spam' => [ + 'title' => 'Bypass spamfilter default value', + 'description' => 'Whether new email accounts have "Bypass spamfilter" activated by default and whether this setting is adjustable by the customer.
Default: Deactivated, adjustable' + ], + 'default_spam_rewrite_subject' => [ + 'title' => 'Rewrite subject default value', + 'description' => 'Whether new email accounts have "Rewrite subject" activated by default and whether this setting is adjustable by the customer.
Default: Activated, adjustable' + ], + 'default_policy_greylist' => [ + 'title' => 'Use greylisting default value', + 'description' => 'Whether new email accounts have "Use greylisting" activated by default and whether this setting is adjustable by the customer.
Default: Activated, adjustable' + ], ], 'dns' => [ 'destinationip' => 'Domain IP(s)', From b018319b8a3af4f008d22dca5ad0a183d65667ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:39:40 +0100 Subject: [PATCH 02/19] Bump twig/twig from 3.10.3 to 3.11.2 (#1292) Bumps [twig/twig](https://github.com/twigphp/Twig) from 3.10.3 to 3.11.2. - [Changelog](https://github.com/twigphp/Twig/blob/v3.11.2/CHANGELOG) - [Commits](https://github.com/twigphp/Twig/compare/v3.10.3...v3.11.2) --- updated-dependencies: - dependency-name: twig/twig dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 209 +++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 104 deletions(-) diff --git a/composer.lock b/composer.lock index d6752c98..8f6146e7 100644 --- a/composer.lock +++ b/composer.lock @@ -1139,20 +1139,20 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1198,7 +1198,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -1214,7 +1214,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-iconv", @@ -1457,20 +1457,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1517,7 +1517,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1533,7 +1533,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php72", @@ -1686,20 +1686,20 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1746,7 +1746,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -1762,7 +1762,83 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", @@ -1935,16 +2011,16 @@ }, { "name": "twig/twig", - "version": "v3.10.3", + "version": "v3.11.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "67f29781ffafa520b0bbfbd8384674b42db04572" + "reference": "5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", - "reference": "67f29781ffafa520b0bbfbd8384674b42db04572", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1", + "reference": "5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1", "shasum": "" }, "require": { @@ -1952,7 +2028,8 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22" + "symfony/polyfill-php80": "^1.22", + "symfony/polyfill-php81": "^1.29" }, "require-dev": { "psr/container": "^1.0|^2.0", @@ -1998,7 +2075,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.10.3" + "source": "https://github.com/twigphp/Twig/tree/v3.11.2" }, "funding": [ { @@ -2010,7 +2087,7 @@ "type": "tidelift" } ], - "time": "2024-05-16T10:04:27+00:00" + "time": "2024-11-06T18:50:16+00:00" }, { "name": "voku/anti-xss", @@ -4814,82 +4891,6 @@ ], "time": "2024-06-28T09:36:24+00:00" }, - { - "name": "symfony/polyfill-php81", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-06-19T12:30:46+00:00" - }, { "name": "theseer/tokenizer", "version": "1.2.3", From 604078ddc61d48c5a3a605387a4488d4323b562f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 30 Nov 2024 11:19:25 +0100 Subject: [PATCH 03/19] show necessary dns entries for mail/antispan also in admin-view of domain Signed-off-by: Michael Kaufmann --- composer.json | 5 + composer.lock | 307 +++++++++--------- .../admin/domains/formfield.domains_edit.php | 4 +- 3 files changed, 159 insertions(+), 157 deletions(-) diff --git a/composer.json b/composer.json index 93302a77..27a5b428 100644 --- a/composer.json +++ b/composer.json @@ -76,6 +76,11 @@ "ext-apcu": "*", "ext-readline": "*" }, + "config": { + "platform": { + "php": "7.4" + } + }, "autoload": { "psr-4": { "Froxlor\\": [ diff --git a/composer.lock b/composer.lock index 8f6146e7..6864e578 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cf7a156f58ab3f86204a4b4d263621e2", + "content-hash": "d816217447c19befb9f4757a53a7b40e", "packages": [ { "name": "amnuts/opcache-gui", @@ -201,16 +201,16 @@ }, { "name": "league/commonmark", - "version": "2.5.1", + "version": "2.5.3", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "ac815920de0eff6de947eac0a6a94e5ed0fb147c" + "reference": "b650144166dfa7703e62a22e493b853b58d874b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/ac815920de0eff6de947eac0a6a94e5ed0fb147c", - "reference": "ac815920de0eff6de947eac0a6a94e5ed0fb147c", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/b650144166dfa7703e62a22e493b853b58d874b0", + "reference": "b650144166dfa7703e62a22e493b853b58d874b0", "shasum": "" }, "require": { @@ -223,8 +223,8 @@ }, "require-dev": { "cebe/markdown": "^1.0", - "commonmark/cmark": "0.31.0", - "commonmark/commonmark.js": "0.31.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", "composer/package-versions-deprecated": "^1.8", "embed/embed": "^4.4", "erusev/parsedown": "^1.0", @@ -303,7 +303,7 @@ "type": "tidelift" } ], - "time": "2024-07-24T12:52:09+00:00" + "time": "2024-08-16T11:46:16+00:00" }, { "name": "league/config", @@ -674,16 +674,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.1", + "version": "v6.9.2", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18" + "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a7b17b42fa4887c92146243f3d2f4ccb962af17c", + "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c", "shasum": "" }, "require": { @@ -743,7 +743,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.2" }, "funding": [ { @@ -751,7 +751,7 @@ "type": "github" } ], - "time": "2023-11-25T22:23:28+00:00" + "time": "2024-10-09T10:07:50+00:00" }, { "name": "psr/container", @@ -973,16 +973,16 @@ }, { "name": "symfony/console", - "version": "v5.4.42", + "version": "v5.4.47", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cef62396a0477e94fc52e87a17c6e5c32e226b7f" + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cef62396a0477e94fc52e87a17c6e5c32e226b7f", - "reference": "cef62396a0477e94fc52e87a17c6e5c32e226b7f", + "url": "https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", "shasum": "" }, "require": { @@ -1052,7 +1052,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.42" + "source": "https://github.com/symfony/console/tree/v5.4.47" }, "funding": [ { @@ -1068,7 +1068,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:21:55+00:00" + "time": "2024-11-06T11:30:55+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1218,20 +1218,20 @@ }, { "name": "symfony/polyfill-iconv", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "c027e6a3c6aee334663ec21f5852e89738abc805" + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/c027e6a3c6aee334663ec21f5852e89738abc805", - "reference": "c027e6a3c6aee334663ec21f5852e89738abc805", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-iconv": "*" @@ -1278,7 +1278,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" }, "funding": [ { @@ -1294,24 +1294,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1356,7 +1356,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -1372,24 +1372,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1437,7 +1437,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -1453,7 +1453,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1537,36 +1537,28 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "10112722600777e02d2745716b70c5db4ca70442" + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/10112722600777e02d2745716b70c5db4ca70442", - "reference": "10112722600777e02d2745716b70c5db4ca70442", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", + "reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "type": "library", + "type": "metapackage", "extra": { "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -1590,7 +1582,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0" }, "funding": [ { @@ -1606,24 +1598,24 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "ec444d3f3f6505bb28d11afa41e75faadebc10a1" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/ec444d3f3f6505bb28d11afa41e75faadebc10a1", - "reference": "ec444d3f3f6505bb28d11afa41e75faadebc10a1", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1666,7 +1658,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" }, "funding": [ { @@ -1682,7 +1674,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", @@ -1925,16 +1917,16 @@ }, { "name": "symfony/string", - "version": "v5.4.42", + "version": "v5.4.47", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "909cec913edea162a3b2836788228ad45fcab337" + "reference": "136ca7d72f72b599f2631aca474a4f8e26719799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/909cec913edea162a3b2836788228ad45fcab337", - "reference": "909cec913edea162a3b2836788228ad45fcab337", + "url": "https://api.github.com/repos/symfony/string/zipball/136ca7d72f72b599f2631aca474a4f8e26719799", + "reference": "136ca7d72f72b599f2631aca474a4f8e26719799", "shasum": "" }, "require": { @@ -1991,7 +1983,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.42" + "source": "https://github.com/symfony/string/tree/v5.4.47" }, "funding": [ { @@ -2007,20 +1999,20 @@ "type": "tidelift" } ], - "time": "2024-07-20T18:38:32+00:00" + "time": "2024-11-10T20:33:58+00:00" }, { "name": "twig/twig", - "version": "v3.11.2", + "version": "v3.11.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1" + "reference": "3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1", - "reference": "5b580ec1882b54c98cbd8c0f8a3ca5d1904db6b1", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e", + "reference": "3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e", "shasum": "" }, "require": { @@ -2075,7 +2067,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.11.2" + "source": "https://github.com/twigphp/Twig/tree/v3.11.3" }, "funding": [ { @@ -2087,7 +2079,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T18:50:16+00:00" + "time": "2024-11-07T12:34:41+00:00" }, { "name": "voku/anti-xss", @@ -2174,16 +2166,16 @@ }, { "name": "voku/portable-ascii", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "b56450eed252f6801410d810c8e1727224ae0743" + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", - "reference": "b56450eed252f6801410d810c8e1727224ae0743", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", "shasum": "" }, "require": { @@ -2208,7 +2200,7 @@ "authors": [ { "name": "Lars Moelleken", - "homepage": "http://www.moelleken.org/" + "homepage": "https://www.moelleken.org/" } ], "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", @@ -2220,7 +2212,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.1" + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" }, "funding": [ { @@ -2244,7 +2236,7 @@ "type": "tidelift" } ], - "time": "2022-03-08T17:03:00+00:00" + "time": "2024-11-21T01:49:47+00:00" }, { "name": "voku/portable-utf8", @@ -2353,27 +2345,27 @@ "packages-dev": [ { "name": "composer/pcre", - "version": "3.2.0", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.8" + "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.8", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", "phpunit/phpunit": "^8 || ^9" }, "type": "library", @@ -2412,7 +2404,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.2.0" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -2428,7 +2420,7 @@ "type": "tidelift" } ], - "time": "2024-07-25T09:36:02+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/xdebug-handler", @@ -2568,16 +2560,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", "shasum": "" }, "require": { @@ -2616,7 +2608,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" }, "funding": [ { @@ -2624,20 +2616,20 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2024-11-08T17:47:46+00:00" }, { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -2680,9 +2672,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "pdepend/pdepend", @@ -3073,16 +3065,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.9", + "version": "1.12.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e370bcddadaede0c1716338b262346f40d296f82" + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82", - "reference": "e370bcddadaede0c1716338b262346f40d296f82", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", "shasum": "" }, "require": { @@ -3127,39 +3119,39 @@ "type": "github" } ], - "time": "2024-08-01T16:25:18+00:00" + "time": "2024-11-17T14:08:01+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.31", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -3168,7 +3160,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -3197,7 +3189,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -3205,7 +3197,7 @@ "type": "github" } ], - "time": "2024-03-02T06:37:42+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3450,16 +3442,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "9.6.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", "shasum": "" }, "require": { @@ -3474,7 +3466,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-code-coverage": "^9.2.32", "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.4", @@ -3533,7 +3525,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" }, "funding": [ { @@ -3549,7 +3541,7 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2024-09-19T10:50:18+00:00" }, { "name": "sebastian/cli-parser", @@ -4578,16 +4570,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.2", + "version": "3.11.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", "shasum": "" }, "require": { @@ -4654,20 +4646,20 @@ "type": "open_collective" } ], - "time": "2024-07-21T23:26:44+00:00" + "time": "2024-11-16T12:02:36+00:00" }, { "name": "symfony/config", - "version": "v5.4.40", + "version": "v5.4.46", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "d4e1db78421163b98dd9971d247fd0df4a57ee5e" + "reference": "977c88a02d7d3f16904a81907531b19666a08e78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/d4e1db78421163b98dd9971d247fd0df4a57ee5e", - "reference": "d4e1db78421163b98dd9971d247fd0df4a57ee5e", + "url": "https://api.github.com/repos/symfony/config/zipball/977c88a02d7d3f16904a81907531b19666a08e78", + "reference": "977c88a02d7d3f16904a81907531b19666a08e78", "shasum": "" }, "require": { @@ -4717,7 +4709,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.40" + "source": "https://github.com/symfony/config/tree/v5.4.46" }, "funding": [ { @@ -4733,20 +4725,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2024-10-30T07:58:02+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.42", + "version": "v5.4.45", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "c8409889fdbf48b99271930ea0ebcf3ee5e1ceae" + "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c8409889fdbf48b99271930ea0ebcf3ee5e1ceae", - "reference": "c8409889fdbf48b99271930ea0ebcf3ee5e1ceae", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0c199da64bb27e4216ccccb83f451e2ec66b3c4b", + "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b", "shasum": "" }, "require": { @@ -4806,7 +4798,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.42" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.45" }, "funding": [ { @@ -4822,20 +4814,20 @@ "type": "tidelift" } ], - "time": "2024-07-25T13:57:40+00:00" + "time": "2024-10-22T18:49:16+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.41", + "version": "v5.4.45", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "6d29dd9340b372fa603f04e6df4dd76bb808591e" + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/6d29dd9340b372fa603f04e6df4dd76bb808591e", - "reference": "6d29dd9340b372fa603f04e6df4dd76bb808591e", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54", + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54", "shasum": "" }, "require": { @@ -4873,7 +4865,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.41" + "source": "https://github.com/symfony/filesystem/tree/v5.4.45" }, "funding": [ { @@ -4889,7 +4881,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:36:24+00:00" + "time": "2024-10-22T13:05:35+00:00" }, { "name": "theseer/tokenizer", @@ -4969,5 +4961,8 @@ "platform-dev": { "ext-pcntl": "*" }, + "platform-overrides": { + "php": "7.4" + }, "plugin-api-version": "2.6.0" } diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 45585ca3..7dd7f869 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -433,15 +433,17 @@ return [ 'section_d' => [ 'title' => lng('admin.nameserversettings'), 'image' => 'icons/domain_edit.png', - 'visible' => Settings::Get('system.bind_enable') == '1' && $userinfo['change_serversettings'] == '1', + 'visible' => $userinfo['change_serversettings'] == '1', 'fields' => [ 'isbinddomain' => [ + 'visible' => Settings::Get('system.bind_enable') == '1', 'label' => lng('admin.createzonefile'), 'type' => 'checkbox', 'value' => '1', 'checked' => $result['isbinddomain'] ], 'zonefile' => [ + 'visible' => Settings::Get('system.bind_enable') == '1', 'label' => lng('admin.custombindzone'), 'desc' => lng('admin.bindzonewarning'), 'type' => 'text', From 5bb450bcccafa58a2a5ae0c651f8be4b9a951602 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 2 Dec 2024 22:04:14 +0100 Subject: [PATCH 04/19] fix empty firstname/name but set company when editing a customer via API Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Customers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index f0492ed2..3808dc6e 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -1106,7 +1106,7 @@ class Customers extends ApiCommand implements ResourceEntity $email = $this->getParam('email', true, $idna_convert->decode($result['email'])); $name = $this->getParam('name', true, $result['name']); $firstname = $this->getParam('firstname', true, $result['firstname']); - $company_required = (!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname)); + $company_required = ((!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname))) && empty($result['company']); $company = $this->getParam('company', !$company_required, $result['company']); $street = $this->getParam('street', true, $result['street']); $zipcode = $this->getParam('zipcode', true, $result['zipcode']); From 60f51fd746bc1f4ea2169c844220b8fe77a9e791 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 14:35:45 +0100 Subject: [PATCH 05/19] allow cidr (forward slash) in spf settings-regex; fixes #1295 Signed-off-by: Michael Kaufmann --- actions/admin/settings/180.antispam.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/admin/settings/180.antispam.php b/actions/admin/settings/180.antispam.php index b599a443..6a3c67b2 100644 --- a/actions/admin/settings/180.antispam.php +++ b/actions/admin/settings/180.antispam.php @@ -129,7 +129,7 @@ return [ 'settinggroup' => 'spf', 'varname' => 'spf_entry', 'type' => 'text', - 'string_regexp' => '/^v=spf[a-z0-9:~?\s.-]+$/i', + 'string_regexp' => '/^v=spf[a-z0-9:~?\s.-\/]+$/i', 'default' => 'v=spf1 a mx -all', 'save_method' => 'storeSettingField' ], From 665b879ac510ea12a492ade4d0a247665bfc8570 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 14:45:39 +0100 Subject: [PATCH 06/19] correctly create ssl-redirect if let's encrypt is already activated; fixes #1294 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 0ed0fbc9..10e6a97e 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1571,7 +1571,7 @@ class Domains extends ApiCommand implements ResourceEntity } // Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated - if (($result['letsencrypt'] != $letsencrypt || $result['ssl_redirect'] != $ssl_redirect) && $ssl_redirect > 0 && $letsencrypt == 1) { + if ($result['letsencrypt'] != $letsencrypt && $ssl_redirect > 0 && $letsencrypt == 1) { $ssl_redirect = 2; } From b6dadc0d8fbfa1fa5aae4695e5dc85ce5e876a84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:55:58 +0100 Subject: [PATCH 07/19] Bump vite from 4.5.3 to 4.5.5 (#1296) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.5.3 to 4.5.5. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.5/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.5/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0483e44f..db54468a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "postcss": "^8.1.14", "resolve-url-loader": "^5.0.0", "sass": "^1.69.3", - "vite": "^4.5.3", + "vite": "^4.5.5", "vue": "^3.2.37" }, "engines": { @@ -1156,10 +1156,11 @@ } }, "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", + "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", diff --git a/package.json b/package.json index db6ad8a5..9696a9ca 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "postcss": "^8.1.14", "resolve-url-loader": "^5.0.0", "sass": "^1.69.3", - "vite": "^4.5.3", + "vite": "^4.5.5", "vue": "^3.2.37" }, "engines": { From dcaff3f7de64de6257ffd84aef196f6fd9a0403b Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 15:00:11 +0100 Subject: [PATCH 08/19] set sender-address of emails which were sent using an admin/a reseller to the global settings email so sending it using provided smtp settings will not fail antispam checks; fixes #1289 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/EmailAccounts.php | 8 ++++++-- lib/Froxlor/Cron/Traffic/ReportsCron.php | 8 ++++++-- lib/Froxlor/System/Mailer.php | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index df7f73ca..707a816d 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -260,7 +260,9 @@ class EmailAccounts extends ApiCommand implements ResourceEntity $_mailerror = false; $mailerr_msg = ""; try { - $this->mailer()->setFrom($admin['email'], User::getCorrectUserSalutation($admin)); + $this->mailer()->setFrom(Settings::Get('panel.adminmail'), User::getCorrectUserSalutation($admin)); + $this->mailer()->clearReplyTos(); + $this->mailer()->addReplyTo($admin['email'], User::getCorrectUserSalutation($admin)); $this->mailer()->Subject = $mail_subject; $this->mailer()->AltBody = $mail_body; $this->mailer()->msgHTML(str_replace("\n", "
", $mail_body)); @@ -290,7 +292,9 @@ class EmailAccounts extends ApiCommand implements ResourceEntity $_mailerror = false; try { - $this->mailer()->setFrom($admin['email'], User::getCorrectUserSalutation($admin)); + $this->mailer()->setFrom(Settings::Get('panel.adminmail'), User::getCorrectUserSalutation($admin)); + $this->mailer()->clearReplyTos(); + $this->mailer()->addReplyTo($admin['email'], User::getCorrectUserSalutation($admin)); $this->mailer()->Subject = $mail_subject; $this->mailer()->AltBody = $mail_body; $this->mailer()->msgHTML(str_replace("\n", "
", $mail_body)); diff --git a/lib/Froxlor/Cron/Traffic/ReportsCron.php b/lib/Froxlor/Cron/Traffic/ReportsCron.php index 4a124b89..690e6d2e 100644 --- a/lib/Froxlor/Cron/Traffic/ReportsCron.php +++ b/lib/Froxlor/Cron/Traffic/ReportsCron.php @@ -133,7 +133,9 @@ class ReportsCron extends FroxlorCron $_mailerror = false; $mailerr_msg = ""; try { - $mail->SetFrom($row['adminmail'], $row['adminname']); + $mail->setFrom(Settings::Get('panel.adminmail'), $row['adminname']); + $mail->clearReplyTos(); + $mail->addReplyTo($row['adminmail'], $row['adminname']); $mail->Subject = $mail_subject; $mail->AltBody = $mail_body; $mail->MsgHTML(nl2br($mail_body)); @@ -405,7 +407,9 @@ class ReportsCron extends FroxlorCron $_mailerror = false; $mailerr_msg = ""; try { - $mail->SetFrom($row['adminmail'], $row['adminname']); + $mail->setFrom(Settings::Get('panel.adminmail'), $row['adminname']); + $mail->clearReplyTos(); + $mail->addReplyTo($row['adminmail'], $row['adminname']); $mail->Subject = $mail_subject; $mail->AltBody = $mail_body; $mail->MsgHTML(nl2br($mail_body)); diff --git a/lib/Froxlor/System/Mailer.php b/lib/Froxlor/System/Mailer.php index b8b11cc8..be50f84f 100644 --- a/lib/Froxlor/System/Mailer.php +++ b/lib/Froxlor/System/Mailer.php @@ -68,9 +68,9 @@ class Mailer extends PHPMailer if (self::ValidateAddress(Settings::Get('panel.adminmail')) !== false) { // set return-to address and custom sender-name, see #76 - $this->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname')); + $this->setFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname')); if (Settings::Get('panel.adminmail_return') != '') { - $this->AddReplyTo(Settings::Get('panel.adminmail_return'), Settings::Get('panel.adminmail_defname')); + $this->addReplyTo(Settings::Get('panel.adminmail_return'), Settings::Get('panel.adminmail_defname')); } } } From 2bb863baac12661e1355e835f08dbca109466a94 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 16:15:32 +0100 Subject: [PATCH 09/19] fix regex for spf entry; refs #1295 Signed-off-by: Michael Kaufmann --- actions/admin/settings/180.antispam.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/admin/settings/180.antispam.php b/actions/admin/settings/180.antispam.php index 6a3c67b2..8c3ad4b5 100644 --- a/actions/admin/settings/180.antispam.php +++ b/actions/admin/settings/180.antispam.php @@ -129,7 +129,7 @@ return [ 'settinggroup' => 'spf', 'varname' => 'spf_entry', 'type' => 'text', - 'string_regexp' => '/^v=spf[a-z0-9:~?\s.-\/]+$/i', + 'string_regexp' => '/^v=spf[a-z0-9:~?\s\.\-\/]+$/i', 'default' => 'v=spf1 a mx -all', 'save_method' => 'storeSettingField' ], From 079047b9feb95efc04d6b3b5bdb02c58e61fd152 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 17:01:28 +0100 Subject: [PATCH 10/19] fix permissions of global mysql-user for customers; fixes #1286 Signed-off-by: Michael Kaufmann --- customer_mysql.php | 2 +- install/froxlor.sql.php | 2 +- install/updates/froxlor/update_2.2.inc.php | 35 +++++++++ lib/Froxlor/Api/Commands/Customers.php | 2 +- lib/Froxlor/Api/Commands/Mysqls.php | 6 +- lib/Froxlor/Database/DbManager.php | 28 ++++++- .../Database/Manager/DbManagerMySQL.php | 78 ++++++++++++++++++- lib/Froxlor/Froxlor.php | 2 +- 8 files changed, 142 insertions(+), 13 deletions(-) diff --git a/customer_mysql.php b/customer_mysql.php index e2372448..2a28ef25 100644 --- a/customer_mysql.php +++ b/customer_mysql.php @@ -228,7 +228,7 @@ if ($page == 'overview' || $page == 'mysqls') { $new_password = Crypt::validatePassword(Request::post('mysql_password')); foreach ($allowed_mysqlservers as $dbserver) { // require privileged access for target db-server - Database::needRoot(true, $dbserver, false); + Database::needRoot(true, $dbserver, true); // get DbManager $dbm = new DbManager($log); // give permission to the user on every access-host we have diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 53d7be99..0c4a71e1 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -734,7 +734,7 @@ opcache.validate_timestamps'), ('panel', 'settings_mode', '0'), ('panel', 'menu_collapsed', '1'), ('panel', 'version', '2.2.5'), - ('panel', 'db_version', '202411200'); + ('panel', 'db_version', '202412030'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index 4efaf797..2c773ab1 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -24,6 +24,7 @@ */ use Froxlor\Database\Database; +use Froxlor\Database\DbManager; use Froxlor\Froxlor; use Froxlor\Install\Update; use Froxlor\Settings; @@ -209,3 +210,37 @@ if (Froxlor::isDatabaseVersion('202409280')) { Froxlor::updateToDbVersion('202411200'); } + +if (Froxlor::isDatabaseVersion('202411200')) { + + Update::showUpdateStep("Adjusting customer mysql global user"); + // get all customers that are not deactivated and that have at least one database (hence a global database-user) + $customers = Database::query(" + SELECT DISTINCT c.loginname, c.allowed_mysqlserver + FROM `" . TABLE_PANEL_CUSTOMERS . "` c + LEFT JOIN `" . TABLE_PANEL_DATABASES . "` d ON c.customerid = d.customerid + WHERE c.deactivated = '0' AND d.id IS NOT NULL + "); + while ($customer = $customers->fetch(\PDO::FETCH_ASSOC)) { + $current_allowed_mysqlserver = !empty($customer['allowed_mysqlserver']) ? json_decode($customer['allowed_mysqlserver'], true) : []; + foreach ($current_allowed_mysqlserver as $dbserver) { + // require privileged access for target db-server + Database::needRoot(true, $dbserver, true); + // get DbManager + $dbm = new DbManager($this->logger()); + foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) { + if ($dbm->getManager()->userExistsOnHost($customer['loginname'], $mysql_access_host)) { + // deactivate temporarily + $dbm->getManager()->disableUser($customer['loginname'], $mysql_access_host); + // re-enable + $dbm->getManager()->enableUser($customer['loginname'], $mysql_access_host, true); + } + } + $dbm->getManager()->flushPrivileges(); + Database::needRoot(false); + } + } + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202412030'); +} diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 3808dc6e..0f193c23 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -1347,7 +1347,7 @@ class Customers extends ApiCommand implements ResourceEntity $current_allowed_mysqlserver = isset($result['allowed_mysqlserver']) && !empty($result['allowed_mysqlserver']) ? json_decode($result['allowed_mysqlserver'], true) : []; foreach ($current_allowed_mysqlserver as $dbserver) { // require privileged access for target db-server - Database::needRoot(true, $dbserver, false); + Database::needRoot(true, $dbserver, true); // get DbManager $dbm = new DbManager($this->logger()); foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) { diff --git a/lib/Froxlor/Api/Commands/Mysqls.php b/lib/Froxlor/Api/Commands/Mysqls.php index dcebc412..377afdda 100644 --- a/lib/Froxlor/Api/Commands/Mysqls.php +++ b/lib/Froxlor/Api/Commands/Mysqls.php @@ -113,9 +113,9 @@ class Mysqls extends ApiCommand implements ResourceEntity if (strlen($newdb_params['loginname'] . '_' . $databasename) > Database::getSqlUsernameLength()) { throw new Exception("Database name cannot be longer than " . (Database::getSqlUsernameLength() - strlen($newdb_params['loginname'] . '_')) . " characters.", 406); } - $username = $dbm->createDatabase($newdb_params['loginname'] . '_' . $databasename, $password, $dbserver); + $username = $dbm->createDatabase($newdb_params['loginname'] . '_' . $databasename, $password, $dbserver, 0, $newdb_params['loginname']); } else { - $username = $dbm->createDatabase($newdb_params['loginname'], $password, $dbserver, $newdb_params['mysql_lastaccountnumber']); + $username = $dbm->createDatabase($newdb_params['loginname'], $password, $dbserver, $newdb_params['mysql_lastaccountnumber'], $newdb_params['loginname']); } // we've checked against the password in dbm->createDatabase @@ -541,7 +541,7 @@ class Mysqls extends ApiCommand implements ResourceEntity // Begin root-session Database::needRoot(true, $result['dbserver'], false); $dbm = new DbManager($this->logger()); - $dbm->getManager()->deleteDatabase($result['databasename']); + $dbm->getManager()->deleteDatabase($result['databasename'], $customer['loginname']); Database::needRoot(false); // End root-session diff --git a/lib/Froxlor/Database/DbManager.php b/lib/Froxlor/Database/DbManager.php index 2fdae1e6..8ef72dab 100644 --- a/lib/Froxlor/Database/DbManager.php +++ b/lib/Froxlor/Database/DbManager.php @@ -102,8 +102,26 @@ class DbManager $databases[$databases_row['dbserver']][] = $databases_row['databasename']; } + $customers_sel = Database::query(" + SELECT DISTINCT c.loginname + FROM `" . TABLE_PANEL_CUSTOMERS . "` c + LEFT JOIN `" . TABLE_PANEL_DATABASES . "` d ON c.customerid = d.customerid + WHERE c.deactivated = '0' AND d.id IS NOT NULL + "); + $customers = []; + while ($customer = $customers_sel->fetch(\PDO::FETCH_ASSOC)) { + $customers[] = $customer['loginname']; + } + $dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`"); while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) { + + // add all customer loginnames to the $databases array for this database-server to correct + // a possible existing global mysql-user for that customer + foreach ($customers as $customer) { + $databases[$dbserver['dbserver']][] = $customer; + } + // require privileged access for target db-server Database::needRoot(true, $dbserver['dbserver'], false); @@ -136,6 +154,8 @@ class DbManager $dbm->getManager()->flushPrivileges(); Database::needRoot(false); + + unset($databases[$dbserver['dbserver']]); } } @@ -149,13 +169,14 @@ class DbManager * @param ?string $password * @param int $dbserver * @param int $last_accnumber + * @param ?string $global_user * * @return string|bool $username if successful or false of username is equal to the password * @throws Exception */ - public function createDatabase(string $loginname = null, string $password = null, int $dbserver = 0, int $last_accnumber = 0) + public function createDatabase(string $loginname = null, string $password = null, int $dbserver = 0, int $last_accnumber = 0, string $global_user = "") { - Database::needRoot(true, $dbserver, false); + Database::needRoot(true, $dbserver, true); // check whether we shall create a random username if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'RANDOM') { @@ -184,6 +205,9 @@ class DbManager // and give permission to the user on every access-host we have foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) { $this->getManager()->grantPrivilegesTo($username, $password, $mysql_access_host); + if (!empty($global_user)) { + $this->getManager()->grantCreateToDb($global_user, $username, $mysql_access_host); + } } $this->getManager()->flushPrivileges(); diff --git a/lib/Froxlor/Database/Manager/DbManagerMySQL.php b/lib/Froxlor/Database/Manager/DbManagerMySQL.php index 481c4dc3..178354cd 100644 --- a/lib/Froxlor/Database/Manager/DbManagerMySQL.php +++ b/lib/Froxlor/Database/Manager/DbManagerMySQL.php @@ -110,13 +110,21 @@ class DbManagerMySQL "password" => $password ]); // grant privileges + $grants = "ALL"; + if ($grant_access_prefix) { + $grants = "SELECT, INSERT, UPDATE, DELETE, DROP, INDEX, ALTER"; + } $stmt = Database::prepare(" - GRANT ALL ON `" . $username . ($grant_access_prefix ? '%' : '') . "`.* TO :username@:host + GRANT " . $grants . " ON `" . $username . ($grant_access_prefix ? '%' : '') . "`.* TO :username@:host "); Database::pexecute($stmt, [ "username" => $username, "host" => $access_host ]); + + if ($grant_access_prefix) { + $this->grantCreateToCustomerDbs($username, $access_host); + } } else { // set password if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.6', '<') || version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '10.0.0', '>=')) { @@ -145,9 +153,10 @@ class DbManagerMySQL * takes away any privileges from a user to that db * * @param string $dbname + * @param ?string $global_user * @throws \Exception */ - public function deleteDatabase(string $dbname) + public function deleteDatabase(string $dbname, string $global_user = "") { if (version_compare(Database::getAttribute(PDO::ATTR_SERVER_VERSION), '5.0.2', '<')) { // failsafe if user has been deleted manually (requires MySQL 4.1.2+) @@ -167,11 +176,19 @@ class DbManagerMySQL } else { $drop_stmt = Database::prepare("DROP USER IF EXISTS :dbname@:host"); } + $rev_stmt = Database::prepare("REVOKE ALL PRIVILEGES ON `" . $dbname . "`.* FROM :guser@:host;"); while ($host = $host_res_stmt->fetch(PDO::FETCH_ASSOC)) { Database::pexecute($drop_stmt, [ 'dbname' => $dbname, 'host' => $host['Host'] ], false); + + if (!empty($global_user)) { + Database::pexecute($rev_stmt, [ + 'guser' => $global_user, + 'host' => $host['Host'] + ], false); + } } $drop_stmt = Database::prepare("DROP DATABASE IF EXISTS `" . $dbname . "`"); @@ -231,8 +248,15 @@ class DbManagerMySQL { // check whether user exists to avoid errors if ($this->userExistsOnHost($username, $host)) { - Database::query('GRANT ALL PRIVILEGES ON `' . $username . ($grant_access_prefix ? '%' : '') . '`.* TO `' . $username . '`@`' . $host . '`'); - Database::query('GRANT ALL PRIVILEGES ON `' . str_replace('_', '\_', $username) . ($grant_access_prefix ? '%' : '') . '` . * TO `' . $username . '`@`' . $host . '`'); + $grants = "ALL PRIVILEGES"; + if ($grant_access_prefix) { + $grants = "SELECT, INSERT, UPDATE, DELETE, DROP, INDEX, ALTER"; + } + Database::query('GRANT ' . $grants . ' ON `' . $username . ($grant_access_prefix ? '%' : '') . '`.* TO `' . $username . '`@`' . $host . '`'); + Database::query('GRANT ' . $grants . ' ON `' . str_replace('_', '\_', $username) . ($grant_access_prefix ? '%' : '') . '` . * TO `' . $username . '`@`' . $host . '`'); + if ($grant_access_prefix) { + $this->grantCreateToCustomerDbs($username, $host); + } } } @@ -292,4 +316,50 @@ class DbManagerMySQL } return $allsqlusers; } + + /** + * grant "CREATE" for prefix user to all existing databases of that customer + * + * @param string $username + * @param string $access_host + * @return void + * @throws \Exception + */ + private function grantCreateToCustomerDbs(string $username, string $access_host) + { + $cus_stmt = Database::prepare("SELECT customerid FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE loginname = :username"); + $cust = Database::pexecute_first($cus_stmt, ['username' => $username]); + if ($cust) { + $sel_stmt = Database::prepare("SELECT databasename FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid"); + Database::pexecute($sel_stmt, ['cid' => $cust['customerid']]); + while ($dbdata = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) { + $stmt = Database::prepare(" + GRANT CREATE ON `" . $dbdata['databasename'] . "`.* TO :username@:host + "); + Database::pexecute($stmt, [ + "username" => $username, + "host" => $access_host + ]); + } + } + } + + /** + * grant "CREATE" for prefix user to all existing databases of that customer + * + * @param string $username + * @param string $access_host + * @return void + * @throws \Exception + */ + public function grantCreateToDb(string $username, string $database, string $access_host) + { + $stmt = Database::prepare(" + GRANT CREATE ON `" . $database . "`.* TO :username@:host + "); + Database::pexecute($stmt, [ + "username" => $username, + "host" => $access_host + ]); + } } diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index dadd7cae..a2e3a465 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -34,7 +34,7 @@ final class Froxlor const VERSION = '2.2.5'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202411200'; + const DBVERSION = '202412030'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; From a839d76d1ff38ddba11392c2d0ac281b34ac3400 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Dec 2024 21:20:26 +0100 Subject: [PATCH 11/19] adjust permissions for customer global mysql user to access existing databases Signed-off-by: Michael Kaufmann --- install/updates/froxlor/update_2.2.inc.php | 3 ++- lib/Froxlor/Database/Manager/DbManagerMySQL.php | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index 2c773ab1..ae61ad40 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -26,6 +26,7 @@ use Froxlor\Database\Database; use Froxlor\Database\DbManager; use Froxlor\Froxlor; +use Froxlor\FroxlorLogger; use Froxlor\Install\Update; use Froxlor\Settings; @@ -227,7 +228,7 @@ if (Froxlor::isDatabaseVersion('202411200')) { // require privileged access for target db-server Database::needRoot(true, $dbserver, true); // get DbManager - $dbm = new DbManager($this->logger()); + $dbm = new DbManager(FroxlorLogger::getInstanceOf()); foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) { if ($dbm->getManager()->userExistsOnHost($customer['loginname'], $mysql_access_host)) { // deactivate temporarily diff --git a/lib/Froxlor/Database/Manager/DbManagerMySQL.php b/lib/Froxlor/Database/Manager/DbManagerMySQL.php index 178354cd..b73992a4 100644 --- a/lib/Froxlor/Database/Manager/DbManagerMySQL.php +++ b/lib/Froxlor/Database/Manager/DbManagerMySQL.php @@ -334,7 +334,7 @@ class DbManagerMySQL Database::pexecute($sel_stmt, ['cid' => $cust['customerid']]); while ($dbdata = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) { $stmt = Database::prepare(" - GRANT CREATE ON `" . $dbdata['databasename'] . "`.* TO :username@:host + GRANT ALL ON `" . $dbdata['databasename'] . "`.* TO :username@:host "); Database::pexecute($stmt, [ "username" => $username, @@ -348,6 +348,7 @@ class DbManagerMySQL * grant "CREATE" for prefix user to all existing databases of that customer * * @param string $username + * @param string $database * @param string $access_host * @return void * @throws \Exception @@ -355,7 +356,7 @@ class DbManagerMySQL public function grantCreateToDb(string $username, string $database, string $access_host) { $stmt = Database::prepare(" - GRANT CREATE ON `" . $database . "`.* TO :username@:host + GRANT ALL ON `" . $database . "`.* TO :username@:host "); Database::pexecute($stmt, [ "username" => $username, From 9dec83fff23167c1c11dd3c9804f2d8f4d89a9f8 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 9 Dec 2024 08:57:18 +0100 Subject: [PATCH 12/19] can-edit-domain is not required to create subdomains of that domain if subdomains are allowed Signed-off-by: Michael Kaufmann --- customer_domains.php | 1 - 1 file changed, 1 deletion(-) diff --git a/customer_domains.php b/customer_domains.php index c87105c0..95f48f6e 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -141,7 +141,6 @@ if ($page == 'overview' || $page == 'domains') { WHERE `customerid` = :customerid AND `parentdomainid` = '0' AND `email_only` = '0' - AND `caneditdomain` = '1' AND `deactivated` = '0' ORDER BY `domain` ASC"); Database::pexecute($stmt, [ From 0aa3e2f7b1f9bc345fdac19fd61f7a7a436b1aac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 08:20:53 +0100 Subject: [PATCH 13/19] Bump league/commonmark from 2.5.3 to 2.6.0 (#1298) Bumps [league/commonmark](https://github.com/thephpleague/commonmark) from 2.5.3 to 2.6.0. - [Release notes](https://github.com/thephpleague/commonmark/releases) - [Changelog](https://github.com/thephpleague/commonmark/blob/2.6/CHANGELOG.md) - [Commits](https://github.com/thephpleague/commonmark/compare/2.5.3...2.6.0) --- updated-dependencies: - dependency-name: league/commonmark dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/composer.lock b/composer.lock index 6864e578..b542b23d 100644 --- a/composer.lock +++ b/composer.lock @@ -201,16 +201,16 @@ }, { "name": "league/commonmark", - "version": "2.5.3", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0" + "reference": "d150f911e0079e90ae3c106734c93137c184f932" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/b650144166dfa7703e62a22e493b853b58d874b0", - "reference": "b650144166dfa7703e62a22e493b853b58d874b0", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932", + "reference": "d150f911e0079e90ae3c106734c93137c184f932", "shasum": "" }, "require": { @@ -235,8 +235,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 || ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0" }, @@ -246,7 +247,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.6-dev" + "dev-main": "2.7-dev" } }, "autoload": { @@ -303,7 +304,7 @@ "type": "tidelift" } ], - "time": "2024-08-16T11:46:16+00:00" + "time": "2024-12-07T15:34:16+00:00" }, { "name": "league/config", @@ -1072,16 +1073,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", "shasum": "" }, "require": { @@ -1119,7 +1120,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" }, "funding": [ { @@ -1135,7 +1136,7 @@ "type": "tidelift" } ], - "time": "2023-01-24T14:02:46+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1696,8 +1697,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { From 0fb9357e8719ac0ed85303aa0c591018536baae3 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 10 Dec 2024 20:15:41 +0100 Subject: [PATCH 14/19] set cookie SameSite option to 'Lax' for loginlinks to work as intended; fixes #1299 Signed-off-by: Michael Kaufmann --- lib/Froxlor/UI/Panel/UI.php | 2 +- lib/init.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Froxlor/UI/Panel/UI.php b/lib/Froxlor/UI/Panel/UI.php index 3cec80f8..ebad4738 100644 --- a/lib/Froxlor/UI/Panel/UI.php +++ b/lib/Froxlor/UI/Panel/UI.php @@ -121,7 +121,7 @@ class UI 'domain' => self::getCookieHost(), 'secure' => self::requestIsHttps(), 'httponly' => true, - 'samesite' => 'Strict' + 'samesite' => 'Lax' ]); session_start(); diff --git a/lib/init.php b/lib/init.php index c4cc5bdc..ee61f5b8 100644 --- a/lib/init.php +++ b/lib/init.php @@ -374,7 +374,7 @@ if (CurrentUser::hasSession()) { 'domain' => UI::getCookieHost(), 'secure' => UI::requestIsHttps(), 'httponly' => true, - 'samesite' => 'Strict' + 'samesite' => 'Lax' ]; setcookie(session_name(), $_COOKIE[session_name()], $cookie_params); } else { From c2d166c86666f4c50c1402c1b3a2986ddabeee90 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 19 Dec 2024 08:59:00 +0100 Subject: [PATCH 15/19] corrected regex for dns CAA entries; fixes #1300 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/DomainZones.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index 331051cf..dcaa98ab 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -178,7 +178,7 @@ class DomainZones extends ApiCommand implements ResourceEntity } } } elseif ($type == 'CAA' && !empty($content)) { - $re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; + $re = '/(?\'critical\'\d+)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9:\.\/\-]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; preg_match($re, $content, $matches); if (empty($matches)) { From 3638dc08ea4fe55ce0d2458cdcb436cfb5697ed3 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 24 Dec 2024 09:34:59 +0100 Subject: [PATCH 16/19] add new task to (re)configure mail/ftp services with let's encrypt; refs #1297 Signed-off-by: Michael Kaufmann --- actions/admin/settings/131.ssl.php | 4 +- lib/Froxlor/Cli/MasterCron.php | 1 + lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php | 121 ++++++++++++------- lib/Froxlor/Cron/System/TasksCron.php | 7 ++ lib/Froxlor/Cron/TaskId.php | 5 + lib/Froxlor/Settings/Store.php | 11 ++ lng/de.lng.php | 1 + lng/en.lng.php | 1 + 8 files changed, 103 insertions(+), 48 deletions(-) diff --git a/actions/admin/settings/131.ssl.php b/actions/admin/settings/131.ssl.php index 05f5dca7..cfed6178 100644 --- a/actions/admin/settings/131.ssl.php +++ b/actions/admin/settings/131.ssl.php @@ -268,7 +268,7 @@ return [ 'dovecot' => 'dovecot (imap/pop3)', 'proftpd' => 'proftpd (ftp)', ], - 'save_method' => 'storeSettingField', + 'save_method' => 'storeSettingFieldInsertUpdateServicesTask', 'advanced_mode' => true ], 'system_le_renew_hook' => [ @@ -278,7 +278,7 @@ return [ 'type' => 'text', 'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i', 'default' => 'systemctl restart postfix dovecot proftpd', - 'save_method' => 'storeSettingField', + 'save_method' => 'storeSettingFieldInsertUpdateServicesTask', 'advanced_mode' => true, 'required_otp' => true ], diff --git a/lib/Froxlor/Cli/MasterCron.php b/lib/Froxlor/Cli/MasterCron.php index 7045de8e..a8e93f0f 100644 --- a/lib/Froxlor/Cli/MasterCron.php +++ b/lib/Froxlor/Cli/MasterCron.php @@ -80,6 +80,7 @@ final class MasterCron extends CliCommand Cronjob::inserttask(TaskId::REBUILD_RSPAMD); Cronjob::inserttask(TaskId::CREATE_QUOTA); Cronjob::inserttask(TaskId::REBUILD_CRON); + Cronjob::inserttask(TaskId::UPDATE_LE_SERVICES); $jobs[] = 'tasks'; } define('CRON_IS_FORCED', 1); diff --git a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php index 11ee96a3..49bc699f 100644 --- a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php +++ b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php @@ -69,7 +69,8 @@ class AcmeSh extends FroxlorCron * run the task * * @param bool $internal - * @return number + * @return int + * @throws \Exception */ public static function run(bool $internal = false) { @@ -85,6 +86,9 @@ class AcmeSh extends FroxlorCron if ($issue_froxlor || !empty($issue_domains) || !empty($renew_froxlor) || $renew_domains) { // insert task to generate certificates and vhost-configs Cronjob::inserttask(TaskId::REBUILD_VHOST); + if ($renew_froxlor) { + Cronjob::inserttask(TaskId::UPDATE_LE_SERVICES); + } } return 0; } @@ -217,6 +221,7 @@ class AcmeSh extends FroxlorCron * check whether we need to issue a new certificate for froxlor itself * * @return boolean + * @throws \Exception */ private static function issueFroxlorVhost() { @@ -340,6 +345,7 @@ EOC; * check whether we need to renew-check the certificate for froxlor itself * * @return boolean + * @throws \Exception */ private static function renewFroxlorVhost() { @@ -539,6 +545,7 @@ EOC; * @param array $domains * @param int $domain_id * @param FroxlorLogger $cronlog + * @throws \Exception */ private static function validateDns(array &$domains, $domain_id, &$cronlog) { @@ -619,27 +626,47 @@ EOC; $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Successful exit-code returned - storing certificate"); $cert_stored = self::certToDb($certrow, $cronlog, $acme_result); - if ($cert_stored - && $renew_hook - && !empty(trim(Settings::Get('system.le_renew_services') ?? "")) - && !empty(trim(Settings::Get('system.le_renew_hook') ?? "")) - ) { - $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Renew-hook is enabled - adjusting configurations"); + if ($cert_stored && $renew_hook) { + self::renewHookConfigs($cronlog); + } + } + } + } - $certificate_folder = self::getCertificateFolder(strtolower(Settings::Get('system.hostname'))); - $fullchain = FileDir::makeCorrectFile($certificate_folder . '/fullchain.cer'); - $keyfile = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower(Settings::Get('system.hostname')) . '.key'); - $ca_file = FileDir::makeCorrectFile($certificate_folder . '/ca.cer'); + public static function renewHookConfigs($cronlog) + { + if (!empty(trim(Settings::Get('system.le_renew_services') ?? "")) + && !empty(trim(Settings::Get('system.le_renew_hook') ?? "")) + ) { - if (Settings::IsInList('system.le_renew_services', 'postfix')) { - // "postconf -e" for postfix - FileDir::safe_exec('postconf -e smtpd_tls_cert_file=' . escapeshellarg($fullchain)); - FileDir::safe_exec('postconf -e smtpd_tls_key_file=' . escapeshellarg($keyfile)); - } - if (Settings::IsInList('system.le_renew_services', 'dovecot')) { - // custom config for dovecot - $dovecot_conf = '/etc/dovecot/conf.d/99-froxlor.ssl.conf'; // @fixme setting? - $ssl_content = <<logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Renew-hook is enabled - adjusting configurations"); + + $certificate_folder = self::getCertificateFolder(strtolower(Settings::Get('system.hostname'))); + + if (empty($certificate_folder)) { + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No certificate folder for '" . Settings::Get('system.hostname') . "' found"); + return; + } + + $fullchain = FileDir::makeCorrectFile($certificate_folder . '/fullchain.cer'); + $keyfile = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower(Settings::Get('system.hostname')) . '.key'); + $ca_file = FileDir::makeCorrectFile($certificate_folder . '/ca.cer'); + + if (!file_exists($fullchain) || !file_exists($keyfile) || !file_exists($ca_file)) { + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "At least one of the required certificate files for '" . Settings::Get('system.hostname') . "' could not be found"); + return; + } + + $dovecot_conf = '/etc/dovecot/conf.d/99-froxlor.ssl.conf'; // @fixme setting? + + if (Settings::IsInList('system.le_renew_services', 'postfix')) { + // "postconf -e" for postfix + FileDir::safe_exec('postconf -e smtpd_tls_cert_file=' . escapeshellarg($fullchain)); + FileDir::safe_exec('postconf -e smtpd_tls_key_file=' . escapeshellarg($keyfile)); + } + if (Settings::IsInList('system.le_renew_services', 'dovecot')) { + // custom config for dovecot + $ssl_content = <<logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Removing Let's Encrypt entries for domain " . $row['data']['domain']); Domain::doLetsEncryptCleanUp($row['data']['domain']); + } elseif ($row['type'] == TaskId::UPDATE_LE_SERVICES) { + /** + * TYPE=13 set configuration for selected services regarding the use of Let's Encrypt certificate + */ + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Updating Let's Encrypt configuration for selected services"); + AcmeSh::renewHookConfigs(FroxlorLogger::getInstanceOf()); } } diff --git a/lib/Froxlor/Cron/TaskId.php b/lib/Froxlor/Cron/TaskId.php index f905eba4..92d6b629 100644 --- a/lib/Froxlor/Cron/TaskId.php +++ b/lib/Froxlor/Cron/TaskId.php @@ -87,6 +87,11 @@ final class TaskId */ const DELETE_DOMAIN_SSL = 12; + /** + * TYPE=13 set configuration for selected services regarding the use of Let's Encrypt certificate + */ + const UPDATE_LE_SERVICES = 13; + /** * TYPE=20 CUSTUMER DATA DUMP */ diff --git a/lib/Froxlor/Settings/Store.php b/lib/Froxlor/Settings/Store.php index be5f2cb9..bbc6b210 100644 --- a/lib/Froxlor/Settings/Store.php +++ b/lib/Froxlor/Settings/Store.php @@ -237,6 +237,17 @@ class Store return $returnvalue; } + public static function storeSettingFieldInsertUpdateServicesTask($fieldname, $fielddata, $newfieldvalue) + { + // first save the setting itself + $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); + + if ($returnvalue !== false) { + Cronjob::inserttask(TaskId::UPDATE_LE_SERVICES); + } + return $returnvalue; + } + public static function storeSettingHostname($fieldname, $fielddata, $newfieldvalue) { $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); diff --git a/lng/de.lng.php b/lng/de.lng.php index d10d72aa..a876e3d3 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -2192,6 +2192,7 @@ Vielen Dank, Ihr Administrator', 'CREATE_CUSTOMER_DATADUMP' => 'Daten-Export für Kunde %s', 'DELETE_DOMAIN_PDNS' => 'Lösche Domain %s von PowerDNS Datenbank', 'DELETE_DOMAIN_SSL' => 'Lösche SSL Dateien von Domain %s', + 'UPDATE_LE_SERVICES' => 'Aktualisiere Systemdienste für Let\'s Encrypt', ], 'terms' => 'AGB', 'traffic' => [ diff --git a/lng/en.lng.php b/lng/en.lng.php index 4ae337f4..2de83ad3 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -2326,6 +2326,7 @@ Yours sincerely, your administrator', 'CREATE_CUSTOMER_DATADUMP' => 'Data export job for customer %s', 'DELETE_DOMAIN_PDNS' => 'Delete domain %s from PowerDNS database', 'DELETE_DOMAIN_SSL' => 'Delete ssl files of domain %s', + 'UPDATE_LE_SERVICES' => 'Updating system services for Let\'s Encrypt', ], 'terms' => 'Terms of use', 'traffic' => [ From a43d53d54034805e3e404702a01312fa0c40b623 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 Jan 2025 10:27:02 +0100 Subject: [PATCH 17/19] force admin email addresses to be unique and not be used for customers, fixes GHSA-7j6w-p859-464f Signed-off-by: Michael Kaufmann --- composer.lock | 148 ++++++++++++------------- lib/Froxlor/Api/Commands/Admins.php | 23 ++++ lib/Froxlor/Api/Commands/Customers.php | 23 ++++ lng/de.lng.php | 2 + lng/en.lng.php | 2 + 5 files changed, 124 insertions(+), 74 deletions(-) diff --git a/composer.lock b/composer.lock index b542b23d..3378416d 100644 --- a/composer.lock +++ b/composer.lock @@ -201,16 +201,16 @@ }, { "name": "league/commonmark", - "version": "2.6.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "d150f911e0079e90ae3c106734c93137c184f932" + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932", - "reference": "d150f911e0079e90ae3c106734c93137c184f932", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", "shasum": "" }, "require": { @@ -304,7 +304,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T15:34:16+00:00" + "time": "2024-12-29T14:10:59+00:00" }, { "name": "league/config", @@ -675,16 +675,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.2", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a7b17b42fa4887c92146243f3d2f4ccb962af17c", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -744,7 +744,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -752,7 +752,7 @@ "type": "github" } ], - "time": "2024-10-09T10:07:50+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "psr/container", @@ -1090,12 +1090,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1164,8 +1164,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1243,8 +1243,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1320,8 +1320,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1398,8 +1398,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1482,8 +1482,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1556,8 +1556,8 @@ "type": "metapackage", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "notification-url": "https://packagist.org/downloads/", @@ -1621,8 +1621,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1777,8 +1777,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1835,16 +1835,16 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3" + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", "shasum": "" }, "require": { @@ -1860,12 +1860,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1898,7 +1898,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" }, "funding": [ { @@ -1914,7 +1914,7 @@ "type": "tidelift" } ], - "time": "2023-04-21T15:04:16+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/string", @@ -2371,13 +2371,13 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-main": "3.x-dev" } }, "autoload": { @@ -2621,16 +2621,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -2673,9 +2673,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "pdepend/pdepend", @@ -3066,16 +3066,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.11", + "version": "1.12.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733" + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", - "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", "shasum": "" }, "require": { @@ -3120,7 +3120,7 @@ "type": "github" } ], - "time": "2024-11-17T14:08:01+00:00" + "time": "2025-01-05T16:40:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3443,16 +3443,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.21", + "version": "9.6.22", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", "shasum": "" }, "require": { @@ -3463,7 +3463,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.12.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -3526,7 +3526,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22" }, "funding": [ { @@ -3542,7 +3542,7 @@ "type": "tidelift" } ], - "time": "2024-09-19T10:50:18+00:00" + "time": "2024-12-05T13:48:26+00:00" }, { "name": "sebastian/cli-parser", @@ -4571,16 +4571,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.11.1", + "version": "3.11.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87" + "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", - "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", + "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", "shasum": "" }, "require": { @@ -4647,7 +4647,7 @@ "type": "open_collective" } ], - "time": "2024-11-16T12:02:36+00:00" + "time": "2024-12-11T16:04:26+00:00" }, { "name": "symfony/config", @@ -4730,16 +4730,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.45", + "version": "v5.4.48", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b" + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0c199da64bb27e4216ccccb83f451e2ec66b3c4b", - "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", "shasum": "" }, "require": { @@ -4799,7 +4799,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.45" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.48" }, "funding": [ { @@ -4815,7 +4815,7 @@ "type": "tidelift" } ], - "time": "2024-10-22T18:49:16+00:00" + "time": "2024-11-20T10:51:57+00:00" }, { "name": "symfony/filesystem", @@ -4937,7 +4937,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index 26ebb0cd..228f4497 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -287,6 +287,15 @@ class Admins extends ApiCommand implements ResourceEntity 'login' => $loginname ], true, true); + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) { Response::standardError('loginnameexists', $loginname, true); } elseif (preg_match('/^' . preg_quote(Settings::Get('customer.accountprefix'), '/') . '([0-9]+)/', $loginname)) { @@ -298,6 +307,8 @@ class Admins extends ApiCommand implements ResourceEntity Response::standardError('loginnameiswrong', $loginname, true); } elseif (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexists', $email, true); } else { if ($customers_see_all != '1') { $customers_see_all = '0'; @@ -610,8 +621,20 @@ class Admins extends ApiCommand implements ResourceEntity 'admin.email' ], '', true); } + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email and `adminid` <> :adminid + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email, + 'adminid' => $id, + ], true, true); + if (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexists', $email, true); } else { if ($deactivated != '1') { $deactivated = '0'; diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 0f193c23..4e4955ad 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -505,6 +505,15 @@ class Customers extends ApiCommand implements ResourceEntity 'login' => $loginname ], true, true); + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + $mysql_maxlen = Database::getSqlUsernameLength() - strlen(Settings::Get('customer.mysqlprefix')); if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) { Response::standardError('loginnameexists', $loginname, true); @@ -514,6 +523,8 @@ class Customers extends ApiCommand implements ResourceEntity } else { Response::standardError('loginnameiswrong', $loginname, true); } + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexistsanon', $email, true); } $guid = intval(Settings::Get('system.lastguid')) + 1; @@ -1243,6 +1254,18 @@ class Customers extends ApiCommand implements ResourceEntity ], '', true); } elseif (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } else { + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + if ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexistsanon', $email, true); + } } } diff --git a/lng/de.lng.php b/lng/de.lng.php index a876e3d3..f1f75488 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -787,6 +787,8 @@ return [ 'mydocumentroot' => '\'Documentroot\'', 'loginnameexists' => 'Der Login-Name "%s" existiert bereits.', 'emailiswrong' => 'Die E-Mail-Adresse "%s" enthält ungültige Zeichen oder ist nicht vollständig.', + 'emailexists' => 'Die E-Mail-Adresse "%s" wird bereits von einem anderen Admin verwendet', + 'emailexistsanon' => 'Die E-Mail-Adresse "%s" wird bereits verwendet', 'alternativeemailiswrong' => 'Die angegebene alternative E-Mail Adresse "%s", an welche die Zugangsdaten geschickt werden soll, scheint ungültig zu sein.', 'loginnameiswrong' => 'Der Login-Name "%s" enthält ungültige Zeichen.', 'loginnameiswrong2' => 'Der Login-Name enthält zu viele Zeichen, es sind maximal %s Zeichen erlaubt.', diff --git a/lng/en.lng.php b/lng/en.lng.php index 2de83ad3..031314c0 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -858,6 +858,8 @@ return [ 'mydocumentroot' => '\'Documentroot\'', 'loginnameexists' => 'Loginname %s already exists', 'emailiswrong' => 'Email-address %s contains invalid characters or is incomplete', + 'emailexists' => 'Email-address %s already in use by another admin', + 'emailexistsanon' => 'Email-address %s already in use.', 'alternativeemailiswrong' => 'The given alternative email address %s to send the credentials to seems to be invalid', 'loginnameiswrong' => 'Loginname "%s" contains illegal characters.', 'loginnameiswrong2' => 'Loginname contains too many characters. Only %s characters are allowed.', From fde43f80600f1035e1e3d2297411b666d805549a Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 Jan 2025 10:27:44 +0100 Subject: [PATCH 18/19] do not output potentially unsafe content, fixes GHSA-26xq-m8xw-6373 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/SubDomains.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index 1c4870c2..76342d2a 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -503,8 +503,7 @@ class SubDomains extends ApiCommand implements ResourceEntity $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 . "'"); - throw new Exception("Subdomain with " . $key . " could not be found", 404); + throw new Exception("Requested subdomain could not be found", 404); } private function getHasCertValueForDomain(int $domainid, int $parentdomainid): int From ec42003367df64c5645a9d5ee5bcd95c75a82b6c Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 Jan 2025 16:53:05 +0100 Subject: [PATCH 19/19] add safety when unsetting isemaildomain flag in domain, fixes #1305 Signed-off-by: Michael Kaufmann --- admin_domains.php | 19 ++++++++++++++++++- lib/Froxlor/Api/Commands/Domains.php | 10 +++++++++- lib/Froxlor/User.php | 2 +- .../admin/domains/formfield.domains_edit.php | 4 ++++ lng/de.lng.php | 2 ++ lng/en.lng.php | 2 ++ 6 files changed, 36 insertions(+), 3 deletions(-) diff --git a/admin_domains.php b/admin_domains.php index 722cf21b..fbbe0d7a 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -319,7 +319,7 @@ if ($page == 'domains' || $page == 'overview') { $alias_check = $alias_check['count']; $domain_emails_result_stmt = Database::prepare(" - SELECT `email`, `email_full`, `destination`, `popaccountid` AS `number_email_forwarders` + SELECT `email`, `email_full`, `destination`, `popaccountid` FROM `" . TABLE_MAIL_VIRTUAL . "` WHERE `customerid` = :customerid AND `domainid` = :id "); Database::pexecute($domain_emails_result_stmt, [ @@ -593,6 +593,23 @@ if ($page == 'domains' || $page == 'overview') { } echo 0; exit(); + } elseif ($action == 'jqEmaildomainNote') { + $domainid = intval(Request::post('id')); + $newval = intval(Request::post('newval')); + try { + $json_result = Domains::getLocal($userinfo, [ + 'id' => $domainid + ])->get(); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; + if ((int)$newval == 0 && $newval != $result['isemaildomain']) { + echo json_encode(['changed' => true, 'info' => lng('admin.emaildomainwarning')]); + exit(); + } + echo 0; + exit(); } elseif ($action == 'import') { if (Request::post('send') == 'send') { $separator = Validate::validate(Request::post('separator'), 'separator'); diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 10e6a97e..93203e9b 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1063,6 +1063,9 @@ class Domains extends ApiCommand implements ResourceEntity * (default yes), 3 = always, default 0 (never) * @param bool $isemaildomain * optional, allow email usage with this domain, default 0 (false) + * @param bool $emaildomainverified + * optional, when setting $isemaildomain to false, this needs to be set to true to confirm the action in case email addresses exist for this domain, + * default 0 (false) * @param bool $email_only * optional, restrict domain to email usage, default 0 (false) * @param int $selectserveralias @@ -1190,6 +1193,7 @@ class Domains extends ApiCommand implements ResourceEntity $subcanemaildomain = $this->getParam('subcanemaildomain', true, $result['subcanemaildomain']); $isemaildomain = $this->getBoolParam('isemaildomain', true, $result['isemaildomain']); + $emaildomainverified = $this->getBoolParam('emaildomainverified', true, 0); $email_only = $this->getBoolParam('email_only', true, $result['email_only']); $p_serveraliasoption = $this->getParam('selectserveralias', true, -1); $speciallogfile = $this->getBoolParam('speciallogfile', true, $result['speciallogfile']); @@ -1273,7 +1277,7 @@ class Domains extends ApiCommand implements ResourceEntity // count where we are used in email-accounts $domain_emails_result_stmt = Database::prepare(" - SELECT `email`, `email_full`, `destination`, `popaccountid` AS `number_email_forwarders` + SELECT `email`, `email_full`, `destination`, `popaccountid` FROM `" . TABLE_MAIL_VIRTUAL . "` WHERE `customerid` = :customerid AND `domainid` = :id "); Database::pexecute($domain_emails_result_stmt, [ @@ -1296,6 +1300,10 @@ class Domains extends ApiCommand implements ResourceEntity } } + if ($emails > 0 && (int)$isemaildomain == 0 && (int)$result['isemaildomain'] == 1 && (int)$emaildomainverified == 0) { + Response::standardError('emaildomainstillhasaddresses', '', true); + } + // handle change of customer (move domain from customer to customer) if ($customerid > 0 && $customerid != $result['customerid'] && Settings::Get('panel.allow_domain_change_customer') == '1') { // check whether target customer has enough resources diff --git a/lib/Froxlor/User.php b/lib/Froxlor/User.php index c2f7857f..a60ffc06 100644 --- a/lib/Froxlor/User.php +++ b/lib/Froxlor/User.php @@ -152,7 +152,7 @@ class User ]); $customer['emails_used_new'] = (int)$customer_emails['number_emails']; - $customer_emails_result_stmt = Database::prepare('SELECT `email`, `email_full`, `destination`, `popaccountid` AS `number_email_forwarders` FROM `' . TABLE_MAIL_VIRTUAL . '` + $customer_emails_result_stmt = Database::prepare('SELECT `email`, `email_full`, `destination`, `popaccountid` FROM `' . TABLE_MAIL_VIRTUAL . '` WHERE `customerid` = :cid'); Database::pexecute($customer_emails_result_stmt, [ "cid" => $customer['customerid'] diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 7dd7f869..c4b884e1 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -213,6 +213,10 @@ return [ 'type' => 'hidden', 'value' => '0' ], + 'emaildomainverified' => [ + 'type' => 'hidden', + 'value' => '0' + ], ] ], 'section_bssl' => [ diff --git a/lng/de.lng.php b/lng/de.lng.php index f1f75488..89e3c57b 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -504,6 +504,7 @@ return [ 'apiguide' => 'API Guide', 'domain_duplicate' => 'Domain duplizieren', 'domain_duplicate_named' => '%s duplizieren', + 'emaildomainwarning' => '
ACHTUNG: Durch die Änderung dieser Einstellung löschen Sie alle bestehenden E-Mail-Adressen und -Konten unwiderruflich.
', ], 'apikeys' => [ 'no_api_keys' => 'Keine API Keys gefunden', @@ -976,6 +977,7 @@ return [ 'invalidpgppublickey' => 'Der angegebene PGP Public Key ist ungültig', 'invalid_validtime' => 'Wert der valid_time in Sekunden muss zwischen 10 und 120 liegen.', 'customerphpenabledbutnoconfig' => 'Kunde hat PHP aktiviert aber keine PHP-Konfiguration wurde gewählt.', + 'emaildomainstillhasaddresses' => 'Maildomain-Flag kann nicht deaktiviert werden, da für diese Domain noch E-Mail-Adressen vorhanden sind.', ], '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 031314c0..5065b5b1 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -519,6 +519,7 @@ return [ 'backups' => [ 'backups' => 'Backups', ], + 'emaildomainwarning' => '
WARNING: By changing this setting you will delete all existing e-mail addresses and -accounts permanently.
', ], 'apcuinfo' => [ 'clearcache' => 'Clear APCu cache', @@ -1048,6 +1049,7 @@ return [ 'invalidpgppublickey' => 'The PGP Public Key is not valid', 'invalid_validtime' => 'Valid time in seconds can only be between 10 and 120', 'customerphpenabledbutnoconfig' => 'Customer has PHP activated but no PHP-configuration was selected.', + 'emaildomainstillhasaddresses' => 'Cannot deactivate mail-domain flag, as there are still email-addresses for this domain.', ], '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.',