From 537b274b4c50b6d5a28c140d48e955466173b7dc Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 8 Mar 2024 09:23:21 +0100 Subject: [PATCH 01/33] correctly validate if a symlink is within the customers home-directory if it's not an absolute path; fixes #1242 Signed-off-by: Michael Kaufmann --- lib/Froxlor/FileDir.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index acb8fb9a58..0b3b529adb 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -140,6 +140,12 @@ public static function makeCorrectDir(string $dir, string $fixed_homedir = ""): if (is_link($check_dir)) { $original_target = $check_dir; $check_dir = readlink($check_dir); + $link_dir = dirname($original_target); + // check whether the link is relative or absolute + if (substr($check_dir, 0, 1) != '/') { + // relative directory, prepend link_dir + $check_dir = $link_dir . '/' . $check_dir; + } if (substr($check_dir, 0, strlen($fixed_homedir)) != $fixed_homedir) { throw new Exception("Found symlink pointing outside of customer home directory: " . substr($original_target, strlen($fixed_homedir))); } @@ -287,7 +293,7 @@ public static function getUnknownDomainTemplate(string $servername = "") $tpl_content = lng('admin.templates.unconfigured_content_fallback'); } } - $redirect_file = FileDir::makeCorrectFile(Froxlor::getInstallDir().'/notice.'.$tpl_ext); + $redirect_file = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/notice.' . $tpl_ext); file_put_contents($redirect_file, $tpl_content); return basename($redirect_file); } From ee7b47c3c0faf4b6623281b0204190d3e7c426f3 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 11 Mar 2024 08:00:26 +0100 Subject: [PATCH 02/33] correctly save pass_authorizationheader flag for php-configs if FCGID is used; correctly add 'FcgidPassHeader' for froxlor-vhost itself if set Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/PhpSettings.php | 16 +++++++--------- lib/Froxlor/Cron/Http/Apache.php | 4 +++- .../admin/phpconfig/formfield.phpconfig_add.php | 2 +- .../admin/phpconfig/formfield.phpconfig_edit.php | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/Froxlor/Api/Commands/PhpSettings.php b/lib/Froxlor/Api/Commands/PhpSettings.php index 588c04a63b..8c50066080 100644 --- a/lib/Froxlor/Api/Commands/PhpSettings.php +++ b/lib/Froxlor/Api/Commands/PhpSettings.php @@ -222,8 +222,8 @@ public function listingCount() * optional request terminate timeout if FPM is used, default is '60s' * @param string $phpfpm_reqslowtimeout * optional request slowlog timeout if FPM is used, default is '5s' - * @param bool $phpfpm_pass_authorizationheader - * optional whether to pass authorization header to webserver if FPM is used, default is 0 (false) + * @param bool $pass_authorizationheader + * optional whether to pass authorization header to webserver if FPM/FCGID is used, default is 0 (false) * @param bool $override_fpmconfig * optional whether to override fpm-daemon-config value for the following settings if FPM is used, * default is 0 (false) @@ -276,7 +276,7 @@ public function add() $fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, 0); $fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, "60s"); $fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, "5s"); - $fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_pass_authorizationheader', true, 0); + $pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, 0); $override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, 0); $def_fpmconfig = $this->apiCall('FpmDaemons.get', [ @@ -312,7 +312,6 @@ public function add() $fpm_enableslowlog = 0; $fpm_reqtermtimeout = 0; $fpm_reqslowtimeout = 0; - $fpm_pass_authorizationheader = 0; $override_fpmconfig = 0; } elseif (Settings::Get('phpfpm.enabled') == 1) { $fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true); @@ -377,7 +376,7 @@ public function add() 'fpmreqslow' => $fpm_reqslowtimeout, 'phpsettings' => $phpsettings, 'fpmsettingid' => $fpm_config_id, - 'fpmpassauth' => $fpm_pass_authorizationheader, + 'fpmpassauth' => $pass_authorizationheader, 'ofc' => $override_fpmconfig, 'pm' => $pmanager, 'max_children' => $max_children, @@ -464,7 +463,7 @@ private function addForAllCustomers(bool $allow_all_customers, int $config_id) * optional request terminate timeout if FPM is used, default is '60s' * @param string $phpfpm_reqslowtimeout * optional request slowlog timeout if FPM is used, default is '5s' - * @param bool $phpfpm_pass_authorizationheader + * @param bool $pass_authorizationheader * optional whether to pass authorization header to webserver if FPM is used, default is 0 (false) * @param bool $override_fpmconfig * optional whether to override fpm-daemon-config value for the following settings if FPM is used, @@ -516,7 +515,7 @@ public function update() $fpm_enableslowlog = $this->getBoolParam('phpfpm_enable_slowlog', true, $result['fpm_slowlog']); $fpm_reqtermtimeout = $this->getParam('phpfpm_reqtermtimeout', true, $result['fpm_reqterm']); $fpm_reqslowtimeout = $this->getParam('phpfpm_reqslowtimeout', true, $result['fpm_reqslow']); - $fpm_pass_authorizationheader = $this->getBoolParam('phpfpm_pass_authorizationheader', true, $result['pass_authorizationheader']); + $pass_authorizationheader = $this->getBoolParam('pass_authorizationheader', true, $result['pass_authorizationheader']); $override_fpmconfig = $this->getBoolParam('override_fpmconfig', true, $result['override_fpmconfig']); $pmanager = $this->getParam('pm', true, $result['pm']); $max_children = $this->getParam('max_children', true, $result['max_children']); @@ -548,7 +547,6 @@ public function update() $fpm_enableslowlog = 0; $fpm_reqtermtimeout = 0; $fpm_reqslowtimeout = 0; - $fpm_pass_authorizationheader = 0; $override_fpmconfig = 0; } elseif (Settings::Get('phpfpm.enabled') == 1) { $fpm_reqtermtimeout = Validate::validate($fpm_reqtermtimeout, 'phpfpm_reqtermtimeout', '/^([0-9]+)(|s|m|h|d)$/', '', [], true); @@ -614,7 +612,7 @@ public function update() 'fpmreqslow' => $fpm_reqslowtimeout, 'phpsettings' => $phpsettings, 'fpmsettingid' => $fpm_config_id, - 'fpmpassauth' => $fpm_pass_authorizationheader, + 'fpmpassauth' => $pass_authorizationheader, 'ofc' => $override_fpmconfig, 'pm' => $pmanager, 'max_children' => $max_children, diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index f4c6f6d1c7..24f1420e43 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -208,7 +208,9 @@ public function createIpPort() ]; $php = new PhpInterface($domain); $phpconfig = $php->getPhpConfig(Settings::Get('system.mod_fcgid_defaultini_ownvhost')); - + if ($phpconfig['pass_authorizationheader'] == '1') { + $this->virtualhosts_data[$vhosts_filename] .= ' FcgidPassHeader Authorization' . "\n"; + } $starter_filename = FileDir::makeCorrectFile($configdir . '/php-fcgi-starter'); $this->virtualhosts_data[$vhosts_filename] .= ' SuexecUserGroup "' . Settings::Get('system.mod_fcgid_httpuser') . '" "' . Settings::Get('system.mod_fcgid_httpgroup') . '"' . "\n"; $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; diff --git a/lib/formfields/admin/phpconfig/formfield.phpconfig_add.php b/lib/formfields/admin/phpconfig/formfield.phpconfig_add.php index 157171f0d4..faa57dbaea 100644 --- a/lib/formfields/admin/phpconfig/formfield.phpconfig_add.php +++ b/lib/formfields/admin/phpconfig/formfield.phpconfig_add.php @@ -103,7 +103,7 @@ 'maxlength' => 10, 'value' => '5s' ], - 'phpfpm_pass_authorizationheader' => [ + 'pass_authorizationheader' => [ 'visible' => Settings::Get('system.webserver') == "apache2", 'label' => lng('admin.phpsettings.pass_authorizationheader'), 'type' => 'checkbox', diff --git a/lib/formfields/admin/phpconfig/formfield.phpconfig_edit.php b/lib/formfields/admin/phpconfig/formfield.phpconfig_edit.php index 8216c27bd0..746616a702 100644 --- a/lib/formfields/admin/phpconfig/formfield.phpconfig_edit.php +++ b/lib/formfields/admin/phpconfig/formfield.phpconfig_edit.php @@ -106,7 +106,7 @@ 'maxlength' => 10, 'value' => $result['fpm_reqslow'] ], - 'phpfpm_pass_authorizationheader' => [ + 'pass_authorizationheader' => [ 'visible' => Settings::Get('system.webserver') == "apache2", 'label' => lng('admin.phpsettings.pass_authorizationheader'), 'type' => 'checkbox', From f22c1db8cb15d60cb66ac91d214dbcc6a5498be7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 Mar 2024 08:08:20 +0100 Subject: [PATCH 03/33] Bump follow-redirects from 1.15.4 to 1.15.6 (#1244) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c81ed2612..b4c4adec0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -776,9 +776,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { From 76c23cf9b1de89908f8ba9e6f89bc1cb42ae84e6 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 17 Mar 2024 08:23:57 +0100 Subject: [PATCH 04/33] wrap SetHandler to php-fpm in file-exists check, as we do for customer-domains already Signed-off-by: Michael Kaufmann --- lib/Froxlor/Cron/Http/Apache.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index 24f1420e43..f3fe3f6b5c 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -281,7 +281,9 @@ public function createIpPort() // start block, cut off last pipe and close block $filesmatch = '(' . str_replace(".", "\.", substr($filesmatch, 0, -1)) . ')'; $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; - $this->virtualhosts_data[$vhosts_filename] .= ' SetHandler proxy:unix:' . $php->getInterface()->getSocketFile() . '|fcgi://localhost' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' SetHandler proxy:unix:' . $php->getInterface()->getSocketFile() . '|fcgi://localhost' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; if ($phpconfig['pass_authorizationheader'] == '1') { $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; From 7c3e89ccc068bc8f44689d2ac84a6ac1584ff0dd Mon Sep 17 00:00:00 2001 From: Wiebe Cazemier Date: Sat, 23 Mar 2024 15:14:11 +0100 Subject: [PATCH 05/33] Fix "expires" option cannot have a year greater than 9999 (#1246) This fixes the exception: '"expires" option cannot have a year greater than 9999', which happens on upgrade from Debian 11 to 12. The session timeout in the DB is 9999999999999, so we constrain the value. --- actions/admin/settings/110.accounts.php | 1 + lib/init.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/actions/admin/settings/110.accounts.php b/actions/admin/settings/110.accounts.php index cff3235665..07e4099a83 100644 --- a/actions/admin/settings/110.accounts.php +++ b/actions/admin/settings/110.accounts.php @@ -35,6 +35,7 @@ 'varname' => 'sessiontimeout', 'type' => 'number', 'min' => 60, + 'max' => 31536000, 'default' => 600, 'save_method' => 'storeSettingField' ], diff --git a/lib/init.php b/lib/init.php index 9b1a67b8fc..4583f68162 100644 --- a/lib/init.php +++ b/lib/init.php @@ -369,7 +369,7 @@ } // update cookie lifetime $cookie_params = [ - 'expires' => time() + Settings::Get('session.sessiontimeout'), + 'expires' => time() + min(Settings::Get('session.sessiontimeout'), 31536000), 'path' => '/', 'domain' => UI::getCookieHost(), 'secure' => UI::requestIsHttps(), From bb83e78c643c9d0908efef62b1a12b2c2fb446c5 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 27 Mar 2024 10:08:13 +0100 Subject: [PATCH 06/33] fix missing csrf tokens for some ajax requests Signed-off-by: Michael Kaufmann --- templates/Froxlor/assets/js/jquery/customer.js | 2 +- templates/Froxlor/assets/js/jquery/domains.js | 6 ++++++ templates/Froxlor/assets/js/jquery/ipsandports.js | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/templates/Froxlor/assets/js/jquery/customer.js b/templates/Froxlor/assets/js/jquery/customer.js index 73ca39dc1b..2be1e1a6d5 100644 --- a/templates/Froxlor/assets/js/jquery/customer.js +++ b/templates/Froxlor/assets/js/jquery/customer.js @@ -31,7 +31,7 @@ export default function () { planid: pid }, dataType: "json", - beforeSend: function(request) { + beforeSend: function (request) { request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content')); }, success: function (json) { diff --git a/templates/Froxlor/assets/js/jquery/domains.js b/templates/Froxlor/assets/js/jquery/domains.js index ede1f1f55d..6826086530 100644 --- a/templates/Froxlor/assets/js/jquery/domains.js +++ b/templates/Froxlor/assets/js/jquery/domains.js @@ -13,6 +13,9 @@ export default function () { customerid: cid }, dataType: "json", + beforeSend: function (request) { + request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content')); + }, success: function (json) { if (json.length > 0) { $('#phpsettingid option').each(function () { @@ -45,6 +48,9 @@ export default function () { id: $('input[name=id]').val(), newval: +$('#speciallogfile').is(':checked') }, dataType: "json", + beforeSend: function (request) { + request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content')); + }, success: function (json) { if (json.changed) { $('#speciallogfile').addClass('is-invalid'); diff --git a/templates/Froxlor/assets/js/jquery/ipsandports.js b/templates/Froxlor/assets/js/jquery/ipsandports.js index a14de4a11d..bc9e0c2814 100644 --- a/templates/Froxlor/assets/js/jquery/ipsandports.js +++ b/templates/Froxlor/assets/js/jquery/ipsandports.js @@ -15,6 +15,9 @@ export default function () { ip: ipval }, dataType: "json", + beforeSend: function (request) { + request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content')); + }, success: function (json) { if (json != 0) { $('#ip').addClass('is-invalid'); From ff4c54a9d5445819f13214ebff763732f7fd99cd Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 27 Mar 2024 10:17:02 +0100 Subject: [PATCH 07/33] also add logfiles to virtual-host if it's a redirect Signed-off-by: Michael Kaufmann --- lib/Froxlor/Cron/Http/Apache.php | 1 + lib/Froxlor/Cron/Http/Lighttpd.php | 1 + lib/Froxlor/Cron/Http/Nginx.php | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index f3fe3f6b5c..609f916489 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -823,6 +823,7 @@ protected function getVhostContent($domain, $ssl_vhost = false) $modrew_red = ' [R=' . $code . ';L,NE]'; } + $vhost_content .= $this->getLogfiles($domain); // redirect everything, not only root-directory, #541 $vhost_content .= ' ' . "\n"; $vhost_content .= ' RewriteEngine On' . "\n"; diff --git a/lib/Froxlor/Cron/Http/Lighttpd.php b/lib/Froxlor/Cron/Http/Lighttpd.php index 968ab62c08..92478a9424 100644 --- a/lib/Froxlor/Cron/Http/Lighttpd.php +++ b/lib/Froxlor/Cron/Http/Lighttpd.php @@ -406,6 +406,7 @@ protected function getVhostContent($domain, $ssl_vhost = false, $ipid = 0) // Get domain's redirect code $code = Domain::getDomainRedirectCode($domain['id']); + $vhost_content .= $this->getLogFiles($domain); $vhost_content .= ' url.redirect-code = ' . $code . "\n"; $vhost_content .= ' url.redirect = (' . "\n"; $vhost_content .= ' "^/(.*)$" => "' . $uri . '$1"' . "\n"; diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index 49246134cb..fe951784c7 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -604,6 +604,7 @@ protected function getVhostContent($domain, $ssl_vhost = false) // Get domain's redirect code $code = Domain::getDomainRedirectCode($domain['id']); + $vhost_content .= $this->getLogFiles($domain); $vhost_content .= "\t" . 'location / {' . "\n"; $vhost_content .= "\t\t" . 'return ' . $code . ' ' . $uri . '$request_uri;' . "\n"; $vhost_content .= "\t" . '}' . "\n"; From 1f4f1d8203166fab7b90e3e7476f46ab26b37d10 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 27 Mar 2024 11:07:55 +0100 Subject: [PATCH 08/33] fix domains speciallogfile ajax-check/note; improve ajax ip check in admin_ipsandports Signed-off-by: Michael Kaufmann --- admin_ipsandports.php | 6 ++++-- templates/Froxlor/assets/js/jquery/domains.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/admin_ipsandports.php b/admin_ipsandports.php index e8f796b3c4..c660bc21c5 100644 --- a/admin_ipsandports.php +++ b/admin_ipsandports.php @@ -142,8 +142,10 @@ } } elseif ($action == 'jqCheckIP') { $ip = $_POST['ip'] ?? ""; - if ((filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE) == false) { - // returns notice if private network detected so we can display it + if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) { + echo json_encode('
'.lng('error.invalidip', [$ip]).'
'); + } elseif (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE)) { + // returns notice if private network detected, so we can display it echo json_encode(lng('admin.ipsandports.ipnote')); } else { echo 0; diff --git a/templates/Froxlor/assets/js/jquery/domains.js b/templates/Froxlor/assets/js/jquery/domains.js index 6826086530..a9b7458d24 100644 --- a/templates/Froxlor/assets/js/jquery/domains.js +++ b/templates/Froxlor/assets/js/jquery/domains.js @@ -48,6 +48,7 @@ export default function () { id: $('input[name=id]').val(), newval: +$('#speciallogfile').is(':checked') }, dataType: "json", + async: false, beforeSend: function (request) { request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content')); }, From b49f20af95ebfbf44ba7e039b2aa660fc025a035 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 27 Mar 2024 12:59:48 +0100 Subject: [PATCH 09/33] fix copy-to-clipboard button Signed-off-by: Michael Kaufmann --- templates/Froxlor/assets/js/jquery/global.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/templates/Froxlor/assets/js/jquery/global.js b/templates/Froxlor/assets/js/jquery/global.js index 067c4dffc6..5127dace48 100644 --- a/templates/Froxlor/assets/js/jquery/global.js +++ b/templates/Froxlor/assets/js/jquery/global.js @@ -12,9 +12,14 @@ export default function () { new bootstrap.Popover($(this)); }) + if (!window.isSecureContext) { + // hide all copyClipboard buttons as this only works in a secure context + $('.copyClipboard').hide(); + } + $('.copyClipboard').on('click', function (e) { e.preventDefault(); - const source_element = $(this).data('clipboard-source').text(); + const source_element = $(this).data('clipboard-source'); navigator.clipboard.writeText($('#' + source_element).text().trim()); }) From 61ae182ba7a009da775535e557915698c9dc4b9f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 29 Mar 2024 11:40:08 +0100 Subject: [PATCH 10/33] update updater to latest stable release; refactored modal-action-button for UI fixed Signed-off-by: Michael Kaufmann --- install/updates/froxlor/update_2.1.inc.php | 10 +++++ install/updates/froxlor/update_2.2.inc.php | 2 +- templates/Froxlor/table/macros.html.twig | 46 +++++++++++++--------- templates/Froxlor/table/table.html.twig | 8 ++++ 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/install/updates/froxlor/update_2.1.inc.php b/install/updates/froxlor/update_2.1.inc.php index 7c65b587d7..3b982ea0c1 100644 --- a/install/updates/froxlor/update_2.1.inc.php +++ b/install/updates/froxlor/update_2.1.inc.php @@ -237,3 +237,13 @@ Update::showUpdateStep("Updating from 2.1.5 to 2.1.6", false); Froxlor::updateToVersion('2.1.6'); } + +if (Froxlor::isFroxlorVersion('2.1.6')) { + Update::showUpdateStep("Updating from 2.1.6 to 2.1.7", false); + Froxlor::updateToVersion('2.1.7'); +} + +if (Froxlor::isFroxlorVersion('2.1.7')) { + Update::showUpdateStep("Updating from 2.1.7 to 2.1.8", false); + Froxlor::updateToVersion('2.1.8'); +} diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index 19b975c6f2..f81f127bfa 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -35,7 +35,7 @@ } } -if (Froxlor::isFroxlorVersion('2.1.6')) { +if (Froxlor::isFroxlorVersion('2.1.8')) { Update::showUpdateStep("Enhancing virtual email table"); Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0;"); Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0;"); diff --git a/templates/Froxlor/table/macros.html.twig b/templates/Froxlor/table/macros.html.twig index c006f4bd7c..3a8e49106b 100644 --- a/templates/Froxlor/table/macros.html.twig +++ b/templates/Froxlor/table/macros.html.twig @@ -52,25 +52,8 @@ {{ data.text }} {% endif %} - {% if data.modal is defined and data.modal is iterable %} - - {% endif %} {% endapply %} + {# the modal-markup if any will be generated using actions_modal()-macro after the table itself #} {% endmacro %} {% macro domainWithSan(data) %} @@ -90,3 +73,30 @@ {% endif %} {% endfor %} {% endmacro %} + +{% macro actions_modal(data) %} + {% for action in data %} + {% if action.visible is not defined or action.visible is defined and action.visible %} + {% apply spaceless %} + {% if action.modal is defined and action.modal is iterable %} + + {% endif %} + {% endapply %} + {% endif %} + {% endfor %} +{% endmacro %} diff --git a/templates/Froxlor/table/table.html.twig b/templates/Froxlor/table/table.html.twig index 6b8ac96b12..3c4384cb58 100644 --- a/templates/Froxlor/table/table.html.twig +++ b/templates/Froxlor/table/table.html.twig @@ -64,6 +64,14 @@ {{ pagination.paging(listing.pagination) }} {% endif %} + {# handle potential modal-html if defined by actions #} + {% for tr in listing.table.tr %} + {% for td in tr.td %} + {% if td.data is iterable and td.data.macro == 'actions' %} + {{ macros.actions_modal(td.data.data) }} + {% endif %} + {% endfor %} + {% endfor %} {% endif %} From 5625503e2ddf92a4e700fabd7d0cbb906ebef782 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 27 Apr 2024 10:22:42 +0200 Subject: [PATCH 11/33] add compatibility for mariadb-dump executable instead of mysqldump Signed-off-by: Michael Kaufmann --- lib/Froxlor/Cron/System/ExportCron.php | 60 ++++++++++++++++---------- lib/Froxlor/Install/Install/Core.php | 10 +++-- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/lib/Froxlor/Cron/System/ExportCron.php b/lib/Froxlor/Cron/System/ExportCron.php index 8def5b7d32..b7cfd10be2 100644 --- a/lib/Froxlor/Cron/System/ExportCron.php +++ b/lib/Froxlor/Cron/System/ExportCron.php @@ -115,30 +115,46 @@ private static function createCustomerExport($data = null, $customerdocroot = nu $has_dbs = false; $current_dbserver = -1; - while ($row = $sel_stmt->fetch()) { - // Get sql_root data for the specific database-server the database resides on - if ($current_dbserver != $row['dbserver']) { - Database::needRoot(true, $row['dbserver']); - Database::needSqlData(); - $sql_root = Database::getSqlData(); - Database::needRoot(false); - // create temporary mysql-defaults file for the connection-credentials/details - $mysqlcnf_file = tempnam("/tmp", "frx"); - $mysqlcnf = "[mysqldump]\npassword=" . $sql_root['passwd'] . "\nhost=" . $sql_root['host'] . "\n"; - if (!empty($sql_root['port'])) { - $mysqlcnf .= "port=" . $sql_root['port'] . "\n"; - } elseif (!empty($sql_root['socket'])) { - $mysqlcnf .= "socket=" . $sql_root['socket'] . "\n"; + + // look for mysqldump + $section = 'mysqldump'; + if (file_exists("/usr/bin/mysqldump")) { + $mysql_dump = '/usr/bin/mysqldump'; + } elseif (file_exists("/usr/local/bin/mysqldump")) { + $mysql_dump = '/usr/local/bin/mysqldump'; + } elseif (file_exists("/usr/bin/mariadb-dump")) { + $mysql_dump = '/usr/bin/mariadb-dump'; + $section = 'mariadb-dump'; + } + if (!isset($mysql_dump)) { + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'mysqldump/mariadb-dump executable could not be found. Please install mysql-client/mariadb-client package.'); + } else { + + while ($row = $sel_stmt->fetch()) { + // Get sql_root data for the specific database-server the database resides on + if ($current_dbserver != $row['dbserver']) { + Database::needRoot(true, $row['dbserver']); + Database::needSqlData(); + $sql_root = Database::getSqlData(); + Database::needRoot(false); + // create temporary mysql-defaults file for the connection-credentials/details + $mysqlcnf_file = tempnam("/tmp", "frx"); + $mysqlcnf = "[".$section."]\npassword=" . $sql_root['passwd'] . "\nhost=" . $sql_root['host'] . "\n"; + if (!empty($sql_root['port'])) { + $mysqlcnf .= "port=" . $sql_root['port'] . "\n"; + } elseif (!empty($sql_root['socket'])) { + $mysqlcnf .= "socket=" . $sql_root['socket'] . "\n"; + } + file_put_contents($mysqlcnf_file, $mysqlcnf); } - file_put_contents($mysqlcnf_file, $mysqlcnf); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> '.basename($mysql_dump) . ' -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql')); + $bool_false = false; + FileDir::safe_exec($mysql_dump . ' --defaults-file=' . escapeshellarg($mysqlcnf_file) . ' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [ + '>' + ]); + $has_dbs = true; + $current_dbserver = $row['dbserver']; } - $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql')); - $bool_false = false; - FileDir::safe_exec('mysqldump --defaults-file=' . escapeshellarg($mysqlcnf_file) . ' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [ - '>' - ]); - $has_dbs = true; - $current_dbserver = $row['dbserver']; } if ($has_dbs) { diff --git a/lib/Froxlor/Install/Install/Core.php b/lib/Froxlor/Install/Install/Core.php index f30e689108..22d45e2bf9 100644 --- a/lib/Froxlor/Install/Install/Core.php +++ b/lib/Froxlor/Install/Install/Core.php @@ -176,15 +176,19 @@ private function backupExistingDatabase(object &$db_root) $filename = "/tmp/froxlor_backup_" . date('YmdHi') . ".sql"; // look for mysqldump + $section = 'mysqldump'; if (file_exists("/usr/bin/mysqldump")) { $mysql_dump = '/usr/bin/mysqldump'; } elseif (file_exists("/usr/local/bin/mysqldump")) { $mysql_dump = '/usr/local/bin/mysqldump'; + } elseif (file_exists("/usr/bin/mariadb-dump")) { + $mysql_dump = '/usr/bin/mariadb-dump'; + $section = 'mariadb-dump'; } // create temporary .cnf file $cnffilename = "/tmp/froxlor_dump.cnf"; - $dumpcnf = "[mysqldump]" . PHP_EOL . "password=\"" . $this->validatedData['mysql_root_pass'] . "\"" . PHP_EOL; + $dumpcnf = "[".$section."]" . PHP_EOL . "password=\"" . $this->validatedData['mysql_root_pass'] . "\"" . PHP_EOL; file_put_contents($cnffilename, $dumpcnf); // make the backup @@ -195,7 +199,7 @@ private function backupExistingDatabase(object &$db_root) @unlink($cnffilename); if (stristr(implode(" ", $output), "error")) { throw new Exception(lng('install.errors.mysqldump_backup_failed')); - } else if (!file_exists($filename)) { + } elseif (!file_exists($filename)) { throw new Exception(lng('install.errors.sql_backup_file_missing')); } } else { @@ -379,7 +383,7 @@ private function doSettings(object &$db_user) $this->updateSetting($upd_stmt, 1, 'system', 'leenabled'); $this->updateSetting($upd_stmt, 1, 'system', 'le_froxlor_enabled'); } - $this->updateSetting($upd_stmt, $this->validatedData['servername'], 'system', 'hostname'); + $this->updateSetting($upd_stmt, strtolower($this->validatedData['servername']), 'system', 'hostname'); $this->updateSetting($upd_stmt, 'en', 'panel', 'standardlanguage'); // TODO: set language $this->updateSetting($upd_stmt, $this->validatedData['mysql_access_host'], 'system', 'mysql_access_host'); $this->updateSetting($upd_stmt, $this->validatedData['webserver'], 'system', 'webserver'); From c1bc42267716dd6703ab657b45bf02f61a22eef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:23:48 +0200 Subject: [PATCH 12/33] Bump vite from 4.5.2 to 4.5.3 (#1247) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.5.2 to 4.5.3. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.3/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.3/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 | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4c4adec0e..b60030b662 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.2", + "vite": "^4.5.3", "vue": "^3.2.37" }, "engines": { @@ -1156,9 +1156,9 @@ } }, "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/package.json b/package.json index 17928d7c10..401e4a1078 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.2", + "vite": "^4.5.3", "vue": "^3.2.37" }, "engines": { From 0109c2d26fa0a207cd9412c59f5c5c9a457839c1 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 12:00:49 +0200 Subject: [PATCH 13/33] do not hide nameserver settings via js if email-only is selected for the domain; fixes #1248 Signed-off-by: Michael Kaufmann --- templates/Froxlor/assets/js/jquery/domains.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/Froxlor/assets/js/jquery/domains.js b/templates/Froxlor/assets/js/jquery/domains.js index a9b7458d24..9e3766ec09 100644 --- a/templates/Froxlor/assets/js/jquery/domains.js +++ b/templates/Froxlor/assets/js/jquery/domains.js @@ -73,7 +73,6 @@ export default function () { $('#section_b').hide(); $('#section_bssl').hide(); $('#section_c').hide(); - $('#section_d').hide(); } /** @@ -85,13 +84,11 @@ export default function () { $('#section_b').hide(); $('#section_bssl').hide(); $('#section_c').hide(); - $('#section_d').hide(); } else { // show sections $('#section_b').show(); $('#section_bssl').show(); $('#section_c').show(); - $('#section_d').show(); } }) From 7d99244b9decf61176239259e460398053008ae8 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 12:11:42 +0200 Subject: [PATCH 14/33] higher delay and dont reset input to wrong value to avoid not being able to enter a date manually without datetime-picker; fixes #1243 Signed-off-by: Michael Kaufmann --- templates/Froxlor/assets/js/jquery/apikeys.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/Froxlor/assets/js/jquery/apikeys.js b/templates/Froxlor/assets/js/jquery/apikeys.js index c5203cd3c1..641c17e0f6 100644 --- a/templates/Froxlor/assets/js/jquery/apikeys.js +++ b/templates/Froxlor/assets/js/jquery/apikeys.js @@ -1,6 +1,6 @@ export default function () { $(function () { - var timer, delay = 500; + var timer, delay = 650; $('div[data-action="apikeys"] #allowed_from').on('keyup change', function () { var _this = $(this); clearTimeout(timer); @@ -54,7 +54,7 @@ export default function () { } else { _this.removeClass('is-invalid'); _this.addClass('is-valid'); - _this.val(data.valid_until); + //_this.val(data.valid_until); } }, error: function (request, status, error) { From d6b8eb08c0940c7cd237c39a56b5ef72d420bcbc Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 13:49:07 +0200 Subject: [PATCH 15/33] add delete-userfiles flag for Domain.delete() to remove email-account data on the filesystem (if any); fixes #1239 Signed-off-by: Michael Kaufmann --- admin_domains.php | 2 +- customer_domains.php | 2 +- lib/Froxlor/Api/Commands/Domains.php | 13 +++++++- lib/Froxlor/Api/Commands/EmailAccounts.php | 2 +- lib/Froxlor/Cron/System/TasksCron.php | 35 ++++------------------ lib/Froxlor/System/Cronjob.php | 2 +- lng/de.lng.php | 2 +- lng/en.lng.php | 2 +- 8 files changed, 23 insertions(+), 37 deletions(-) diff --git a/admin_domains.php b/admin_domains.php index 4675e9fafe..1caeb42eeb 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -113,7 +113,7 @@ } elseif ($alias_check['count'] > 0) { Response::standardError('domains_cantdeletedomainwithaliases'); } else { - HTML::askYesNo('admin_domain_reallydelete', $filename, [ + HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'admin_customer_alsoremovemail', $filename, [ 'id' => $id, 'page' => $page, 'action' => $action diff --git a/customer_domains.php b/customer_domains.php index 94add191dc..e06010a0b2 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -26,7 +26,7 @@ const AREA = 'customer'; require __DIR__ . '/lib/init.php'; -use Froxlor\Api\Commands\SubDomains as SubDomains; +use Froxlor\Api\Commands\SubDomains; use Froxlor\CurrentUser; use Froxlor\Database\Database; use Froxlor\Domain\Domain; diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index ad0d4c5542..52e204e797 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -2098,6 +2098,8 @@ public function update() * @param bool $is_stdsubdomain * optional, default false, specify whether it's a std-subdomain you are deleting as it does not count * as subdomain-resource + * @param bool $delete_userfiles + * optional, delete email account files on filesystem (if any), default false * * @access admin * @return string json-encoded array @@ -2109,7 +2111,8 @@ public function delete() $id = $this->getParam('id', true, 0); $dn_optional = $id > 0; $domainname = $this->getParam('domainname', $dn_optional, ''); - $is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0); + $is_stdsubdomain = $this->getBoolParam('is_stdsubdomain', true, 0); + $delete_user_emailfiles = $this->getBoolParam('delete_userfiles', true, 0); $result = $this->apiCall('Domains.get', [ 'id' => $id, @@ -2133,6 +2136,14 @@ public function delete() $idString = implode(' OR ', $idString); if ($idString != '') { + if ($delete_user_emailfiles) { + // determine all connected email-accounts + $emailaccount_sel = Database::prepare("SELECT `email`, `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString); + Database::pexecute($emailaccount_sel, $paramString, true, true); + while ($emailacc_row = $emailaccount_sel->fetch(PDO::FETCH_ASSOC)) { + Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $emailacc_row['email'], FileDir::makeCorrectDir($emailacc_row['homedir'] . '/' . $emailacc_row['maildir'])); + } + } $del_stmt = Database::prepare(" DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString); Database::pexecute($del_stmt, $paramString, true, true); diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index b69da105ef..4c2cfc3bea 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -563,7 +563,7 @@ public function delete() } if ($delete_userfiles) { - Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']); + Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], FileDir::makeCorrectDir($result['homedir'] . '/' . $result['maildir'])); } // decrease usage for customer diff --git a/lib/Froxlor/Cron/System/TasksCron.php b/lib/Froxlor/Cron/System/TasksCron.php index 83cfdd3f76..b339141fdc 100644 --- a/lib/Froxlor/Cron/System/TasksCron.php +++ b/lib/Froxlor/Cron/System/TasksCron.php @@ -348,24 +348,16 @@ private static function deleteEmailData($row = null) FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'TasksCron: Task7 started - deleting customer e-mail data'); if (is_array($row['data'])) { - if (isset($row['data']['loginname']) && isset($row['data']['email'])) { + if (isset($row['data']['loginname']) && isset($row['data']['emailpath'])) { // remove specific maildir - $email_full = $row['data']['email']; + $email_full = $row['data']['emailpath']; if (empty($email_full)) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but email field is empty!'); - } - $email_user = substr($email_full, 0, strrpos($email_full, "@")); - $email_domain = substr($email_full, strrpos($email_full, "@") + 1); - $maildirname = trim(Settings::Get('system.vmail_maildirname')); - // Add trailing slash to Maildir if needed - $maildirpath = $maildirname; - if (!empty($maildirname) and substr($maildirname, -1) != "/") { - $maildirpath .= "/"; + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but emailpath field is empty!'); } - $maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $email_domain . '/' . $email_user); + $maildir = FileDir::makeCorrectDir($email_full); - if ($maildir != '/' && !empty($maildir) && !empty($email_full) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && is_dir(FileDir::makeCorrectDir($maildir . '/' . $maildirpath)) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) { + if ($maildir != '/' && !empty($maildir) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) { FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir)); // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part $return = false; @@ -377,23 +369,6 @@ private static function deleteEmailData($row = null) '~', '?' ]); - } else { - // backward-compatibility for old folder-structure - $maildir_old = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $row['data']['email']); - - if ($maildir_old != '/' && !empty($maildir_old) && $maildir_old != Settings::Get('system.vmail_homedir') && substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir_old) && fileowner($maildir_old) == Settings::Get('system.vmail_uid') && filegroup($maildir_old) == Settings::Get('system.vmail_gid')) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old)); - // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part - $return = false; - FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir_old), $return, [ - '|', - '&', - '`', - '$', - '~', - '?' - ]); - } } } } diff --git a/lib/Froxlor/System/Cronjob.php b/lib/Froxlor/System/Cronjob.php index b4be07ac2e..16021b3349 100644 --- a/lib/Froxlor/System/Cronjob.php +++ b/lib/Froxlor/System/Cronjob.php @@ -183,7 +183,7 @@ public static function inserttask(int $type, ...$params) } elseif ($type == TaskId::DELETE_EMAIL_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') { $data = []; $data['loginname'] = $params[0]; - $data['email'] = $params[1]; + $data['emailpath'] = $params[1]; $data = json_encode($data); Database::pexecute($ins_stmt, [ 'type' => TaskId::DELETE_EMAIL_DATA, diff --git a/lng/de.lng.php b/lng/de.lng.php index 63923c56f4..104a95fa85 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -1283,7 +1283,7 @@ 'question' => [ 'question' => 'Sicherheitsabfrage', 'admin_customer_reallydelete' => 'Wollen Sie den Kunden "%s" wirklich löschen?
ACHTUNG! Alle Daten gehen unwiderruflich verloren! Nach dem Vorgang müssen die Daten manuell aus dem Dateisystem entfernt werden.', - 'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?', + 'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?
ACHTUNG: Alle Subdomains, FTP-Konten und E-Mail Adressen/Konten, welche mit dieser Domain verbunden sind, werden gelöscht!', 'admin_domain_reallydisablesecuritysetting' => 'Wollen Sie die wichtige Sicherheitseinstellung \'OpenBasedir\' wirklich deaktivieren?', 'admin_admin_reallydelete' => 'Wollen Sie den Admin "%s" wirklich löschen?
Alle Kunden und Domains dieses Admins werden Ihnen zugeteilt.', 'admin_template_reallydelete' => 'Wollen Sie die Vorlage "%s" wirklich löschen?', diff --git a/lng/en.lng.php b/lng/en.lng.php index c1e7bcce5b..ba2c765331 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -1398,7 +1398,7 @@ 'question' => [ 'question' => 'Security question', 'admin_customer_reallydelete' => 'Do you really want to delete the customer %s? This cannot be undone!', - 'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?', + 'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?
NOTE: All subdomains, ftp-accounts and email-addresses/accounts connected to this domain will be removed!', 'admin_domain_reallydisablesecuritysetting' => 'Do you really want to disable this security setting OpenBasedir?', 'admin_admin_reallydelete' => 'Do you really want to delete the admin %s? Every customer and domain will be reassigned to your account.', 'admin_template_reallydelete' => 'Do you really want to delete the template \'%s\'?', From 71746f8dacab04615986d7b8a7c85e5e6e9715f3 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 13:58:27 +0200 Subject: [PATCH 16/33] select homedir/maildir from emails if called by admin Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/Emails.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 4569852f13..007dbea21b 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -221,12 +221,12 @@ public function get() $customer_ids = $this->getAllowedCustomerIds('email'); $params['idea'] = ($id <= 0 ? $emailaddr : $id); - $result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` + $result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` " . ($this->isAdmin() ? ", `u`.`homedir`, `u`.`maildir`" : "") . " FROM `" . TABLE_MAIL_VIRTUAL . "` v LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id` WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ") - AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)") - ); + AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)" + )); $result = Database::pexecute_first($result_stmt, $params, true, true); if ($result) { $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] get email address '" . $result['email_full'] . "'"); From 7f8b36e0bdd682568e816a37a7b1caf769bd451a Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 28 Apr 2024 14:03:38 +0200 Subject: [PATCH 17/33] select homedir/maildir from emails if called interally as it is also called by customers via EmailAccounts.delete() Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/EmailAccounts.php | 2 +- lib/Froxlor/Api/Commands/Emails.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index 4c2cfc3bea..df7f73ca2a 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -523,7 +523,7 @@ public function delete() $result = $this->apiCall('Emails.get', [ 'id' => $id, 'emailaddr' => $emailaddr - ]); + ], true); $id = $result['id']; if (empty($result['popaccountid']) || $result['popaccountid'] == 0) { diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 007dbea21b..60e81f5974 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -221,7 +221,7 @@ public function get() $customer_ids = $this->getAllowedCustomerIds('email'); $params['idea'] = ($id <= 0 ? $emailaddr : $id); - $result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` " . ($this->isAdmin() ? ", `u`.`homedir`, `u`.`maildir`" : "") . " + $result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` " . ($this->isInternal() ? ", `u`.`homedir`, `u`.`maildir`" : "") . " FROM `" . TABLE_MAIL_VIRTUAL . "` v LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id` WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ") From 1b44ee2e06d414f163f41732e92366e36654b08f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 3 May 2024 07:54:13 +0200 Subject: [PATCH 18/33] Merge pull request from GHSA-x525-54hf-xr53 * do not log unvalidated user-input to mysql-log (if enabled) Signed-off-by: Michael Kaufmann * clean log-text to only allow a subset of special characters Signed-off-by: Michael Kaufmann * clean log-text when selecting from database to avoid possible previously added malicious entries Signed-off-by: Michael Kaufmann --------- Signed-off-by: Michael Kaufmann --- index.php | 6 +++--- lib/Froxlor/Api/Commands/SysLog.php | 2 ++ lib/Froxlor/FroxlorLogger.php | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/index.php b/index.php index ee63cbde29..743bfe7132 100644 --- a/index.php +++ b/index.php @@ -272,7 +272,7 @@ $rstlog = FroxlorLogger::getInstanceOf([ 'loginname' => $_SERVER['REMOTE_ADDR'] ]); - $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "Unknown user '" . $loginname . "' tried to login."); + $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "Unknown user tried to login."); Response::redirectTo('index.php', [ 'showmessage' => '2' @@ -334,7 +334,7 @@ $rstlog = FroxlorLogger::getInstanceOf([ 'loginname' => $_SERVER['REMOTE_ADDR'] ]); - $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User '" . $loginname . "' tried to login with wrong password."); + $rstlog->logAction(FroxlorLogger::LOGIN_ACTION, LOG_WARNING, "User tried to login with wrong password."); unset($userinfo); Response::redirectTo('index.php', [ @@ -653,7 +653,7 @@ $rstlog = FroxlorLogger::getInstanceOf([ 'loginname' => 'password_reset' ]); - $rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $loginname . "' requested to set a new password, but was not found in database!"); + $rstlog->logAction(FroxlorLogger::USR_ACTION, LOG_WARNING, "Unknown user requested to set a new password, but was not found in database!"); $message = lng('login.usernotfound'); } diff --git a/lib/Froxlor/Api/Commands/SysLog.php b/lib/Froxlor/Api/Commands/SysLog.php index 9236d57772..2df7d1a133 100644 --- a/lib/Froxlor/Api/Commands/SysLog.php +++ b/lib/Froxlor/Api/Commands/SysLog.php @@ -90,6 +90,8 @@ public function listing() } Database::pexecute($result_stmt, $query_fields, true, true); while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { + // clean log-text + $row['text'] = preg_replace("/[^\w @#\"':.()\[\]+\-_\/\\\!]/i", "_", $row['text']); $result[] = $row; } $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries"); diff --git a/lib/Froxlor/FroxlorLogger.php b/lib/Froxlor/FroxlorLogger.php index 2ca02aeb08..6eeadf7fdc 100644 --- a/lib/Froxlor/FroxlorLogger.php +++ b/lib/Froxlor/FroxlorLogger.php @@ -175,6 +175,9 @@ public function logAction($action = FroxlorLogger::USR_ACTION, int $type = LOG_N $this->initMonolog(); } + // clean log-text + $text = preg_replace("/[^\w @#\"':.()\[\]+\-_\/\\\!]/i", "_", $text); + if (self::$crondebug_flag || ($action == FroxlorLogger::CRON_ACTION && $type <= LOG_WARNING)) { echo "[" . $this->getLogLevelDesc($type) . "] " . $text . PHP_EOL; } From 63b21f385d7857e291cd1808e8991f796865c345 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 3 May 2024 08:36:52 +0200 Subject: [PATCH 19/33] mysql8 does not automatically load mysql_native_password-plugin anymore (should not be necessary anyway) Signed-off-by: Michael Kaufmann --- .github/workflows/build-mysql.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/build-mysql.yml b/.github/workflows/build-mysql.yml index aa774291dc..21927a0743 100644 --- a/.github/workflows/build-mysql.yml +++ b/.github/workflows/build-mysql.yml @@ -39,16 +39,7 @@ jobs: - name: Wait for database run: sleep 15 - - name: Setup database (8.0) - if: matrix.mysql-version == '8.0' - run: | - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED WITH mysql_native_password BY 'fr0xl0r.TravisCI';" - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';" - php -r "echo include('install/froxlor.sql.php');" > /tmp/froxlor.sql - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < /tmp/froxlor.sql - - - name: Setup database (5.7) - if: matrix.mysql-version == '5.7' + - name: Setup database run: | mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED BY 'fr0xl0r.TravisCI';" mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';" From 27753962cfe99da4c6a312ba82a705b76875409a Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 3 May 2024 09:02:22 +0200 Subject: [PATCH 20/33] use default caching_sha2_password auth plugin for mysql8 Signed-off-by: Michael Kaufmann --- lib/Froxlor/Database/DbManager.php | 2 +- lib/Froxlor/Database/Manager/DbManagerMySQL.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Froxlor/Database/DbManager.php b/lib/Froxlor/Database/DbManager.php index eeb1e4431a..4d56906ca5 100644 --- a/lib/Froxlor/Database/DbManager.php +++ b/lib/Froxlor/Database/DbManager.php @@ -110,7 +110,7 @@ public static function correctMysqlUsers(array $mysql_access_host_array) $users = $dbm->getManager()->getAllSqlUsers(false); foreach ($databases[$dbserver['dbserver']] as $username) { - if (isset($users[$username]) && is_array($users[$username]) && isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) { + if (isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) { $password = [ 'password' => $users[$username]['password'], diff --git a/lib/Froxlor/Database/Manager/DbManagerMySQL.php b/lib/Froxlor/Database/Manager/DbManagerMySQL.php index 77e59495ed..a73a1be402 100644 --- a/lib/Froxlor/Database/Manager/DbManagerMySQL.php +++ b/lib/Froxlor/Database/Manager/DbManagerMySQL.php @@ -82,7 +82,8 @@ public function createDatabase(string $dbname = null) */ public function grantPrivilegesTo(string $username, $password, string $access_host = null, bool $p_encrypted = false, bool $update = false, bool $grant_access_prefix = false) { - $pwd_plugin = 'mysql_native_password'; + // this is required for mysql8 + $pwd_plugin = 'caching_sha2_password'; if (is_array($password) && count($password) == 2) { $pwd_plugin = $password['plugin']; $password = $password['password']; @@ -278,7 +279,7 @@ public function getAllSqlUsers(bool $user_only = true): array if (!isset($allsqlusers[$row['User']]) || !is_array($allsqlusers[$row['User']])) { $allsqlusers[$row['User']] = [ 'password' => $row['Password'] ?? $row['authentication_string'], - 'plugin' => $row['plugin'] ?? 'mysql_native_password', + 'plugin' => $row['plugin'] ?? 'caching_sha2_password', 'hosts' => [] ]; } From fc3f0d8ebf558633bf1c03148abb6cccb7e51f92 Mon Sep 17 00:00:00 2001 From: rex2630 Date: Tue, 7 May 2024 19:45:00 +0200 Subject: [PATCH 21/33] Add config for Ubuntu 24.04 - Noble Numbat (#1251) * Add config for Ubuntu 24.04 - Noble Numbat * Use php 8.3 by default --- lib/configfiles/noble.xml | 4295 +++++++++++++++++++++++++++++++++++++ 1 file changed, 4295 insertions(+) create mode 100644 lib/configfiles/noble.xml diff --git a/lib/configfiles/noble.xml b/lib/configfiles/noble.xml new file mode 100644 index 0000000000..8a583a7c05 --- /dev/null +++ b/lib/configfiles/noble.xml @@ -0,0 +1,4295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + {{settings.system.apacheconf_vhost}} + + + + + {{settings.system.apacheconf_vhost}} + + + + + + + {{settings.system.apacheconf_diroptions}} + + + + + {{settings.system.apacheconf_diroptions}} + + + + + + + + + {{settings.system.deactivateddocroot}} + + + + + + + + + //service[@type='http']/general/commands + + + + {{settings.system.use_ssl}} + + + + + {{settings.phpfpm.enabled}} + + + + + {{settings.system.leenabled}} + + + Require all granted +
+]]> + + + + + + + + + "{{settings.system.letsencryptchallengepath}}/.well-known/acme-challenge/") + +# default listening port for IPv6 falls back to the IPv4 port +include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port +include_shell "/usr/share/lighttpd/create-mime.assign.pl" +include_shell "/usr/share/lighttpd/include-conf-enabled.pl" +]]> + + + //service[@type='http']/general/commands + + {{settings.system.apacheconf_vhost}} + + > /etc/lighttpd/lighttpd.conf]]> + + + {{settings.system.apacheconf_vhost}} + + > /etc/lighttpd/lighttpd.conf]]> + + + {{settings.system.apacheconf_diroptions}} + + > /etc/lighttpd/lighttpd.conf]]> + + + {{settings.system.apacheconf_diroptions}} + + > /etc/lighttpd/lighttpd.conf]]> + + + + + + + + + + {{settings.phpfpm.enabled}} + + {{settings.system.mod_fcgid}} + + + + + + + + + + + + + {{settings.system.leenabled}} + + + + + + {{settings.phpfpm.enabled}} + + {{settings.system.mod_fcgid}} + + + + + //service[@type='http']/general/commands + + {{settings.phpfpm.enabled}} + + {{settings.system.mod_fcgid}} + + + + + + + + + + + + > /etc/bind/named.conf.local]]> + + + + + + + + + + +################################# +# allow-dnsupdate-from A global setting to allow DNS updates from these IP ranges. +# +# allow-dnsupdate-from=127.0.0.0/8,::1 + +################################# +# allow-recursion List of subnets that are allowed to recurse +# +allow-recursion=127.0.0.1 + +################################# +# also-notify When notifying a domain, also notify these nameservers +# +# also-notify= + +################################# +# any-to-tcp Answer ANY queries with tc=1, shunting to TCP +# +# any-to-tcp=no + +################################# +# cache-ttl Seconds to store packets in the PacketCache +# +# cache-ttl=20 + +################################# +# carbon-interval Number of seconds between carbon (graphite) updates +# +# carbon-interval=30 + +################################# +# carbon-ourname If set, overrides our reported hostname for carbon stats +# +# carbon-ourname= + +################################# +# carbon-server If set, send metrics in carbon (graphite) format to this server +# +# carbon-server= + +################################# +# chroot If set, chroot to this directory for more security +# +# chroot= + +################################# +# config-dir Location of configuration directory (pdns.conf) +# +config-dir=/etc/powerdns + +################################# +# config-name Name of this virtual configuration - will rename the binary image +# +# config-name= + +################################# +# control-console Debugging switch - don't use +# +# control-console=no + +################################# +# daemon Operate as a daemon +# +daemon=yes + +################################# +# default-ksk-algorithms Default KSK algorithms +# +# default-ksk-algorithms=rsasha256 + +################################# +# default-ksk-size Default KSK size (0 means default) +# +# default-ksk-size=0 + +################################# +# default-soa-mail mail address to insert in the SOA record if none set in the backend +# +# default-soa-mail= + +################################# +# default-soa-name name to insert in the SOA record if none set in the backend +# +# default-soa-name=a.misconfigured.powerdns.server + +################################# +# default-ttl Seconds a result is valid if not set otherwise +# +# default-ttl=3600 + +################################# +# default-zsk-algorithms Default ZSK algorithms +# +# default-zsk-algorithms=rsasha256 + +################################# +# default-zsk-size Default ZSK size (0 means default) +# +# default-zsk-size=0 + +################################# +# direct-dnskey Fetch DNSKEY RRs from backend during DNSKEY synthesis +# +# direct-dnskey=no + +################################# +# disable-axfr Disable zonetransfers but do allow TCP queries +# +# disable-axfr=no + +################################# +# disable-axfr-rectify Disable the rectify step during an outgoing AXFR. Only required for regression testing. +# +# disable-axfr-rectify=no + +################################# +# disable-tcp Do not listen to TCP queries +# +# disable-tcp=no + +################################# +# distributor-threads Default number of Distributor (backend) threads to start +# +# distributor-threads=3 + +################################# +# do-ipv6-additional-processing Do AAAA additional processing +# +# do-ipv6-additional-processing=yes + +################################# +# edns-subnet-processing If we should act on EDNS Subnet options +# +# edns-subnet-processing=no + +################################# +# entropy-source If set, read entropy from this file +# +# entropy-source=/dev/urandom + +################################# +# experimental-api-key REST API Static authentication key (required for API use) +# +# experimental-api-key= + +################################# +# experimental-api-readonly If the JSON API should disallow data modification +# +# experimental-api-readonly=no + +################################# +# experimental-dname-processing If we should support DNAME records +# +# experimental-dname-processing=no + +################################# +# experimental-dnsupdate Enable/Disable DNS update (RFC2136) support. Default is no. +# +# experimental-dnsupdate=no + +################################# +# experimental-json-interface If the webserver should serve JSON data +# +# experimental-json-interface=no + +################################# +# experimental-logfile Filename of the log file for JSON parser +# +# experimental-logfile=/var/log/pdns.log + +################################# +# forward-dnsupdate A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master. +# +# forward-dnsupdate=yes + +################################# +# guardian Run within a guardian process +# +guardian=yes + +################################# +# include-dir Include *.conf files from this directory +# +# include-dir= + +################################# +# launch Which backends to launch and order to query them in +# +# launch= + +################################# +# load-modules Load this module - supply absolute or relative path +# +# load-modules= + +################################# +# local-address Local IP addresses to which we bind +# +local-address=,127.0.0.1 + +################################# +# local-address-nonexist-fail Fail to start if one or more of the local-address's do not exist on this server +# +# local-address-nonexist-fail=yes + +################################# +# local-ipv6 Local IP address to which we bind +# +# local-ipv6= + +################################# +# local-ipv6-nonexist-fail Fail to start if one or more of the local-ipv6 addresses do not exist on this server +# +# local-ipv6-nonexist-fail=yes + +################################# +# local-port The port on which we listen +# +# local-port=53 + +################################# +# log-dns-details If PDNS should log DNS non-erroneous details +# +# log-dns-details=no + +################################# +# log-dns-queries If PDNS should log all incoming DNS queries +# +# log-dns-queries=no + +################################# +# logging-facility Log under a specific facility +# +# logging-facility= + +################################# +# loglevel Amount of logging. Higher is more. Do not set below 3 +# +# loglevel=4 + +################################# +# lua-prequery-script Lua script with prequery handler +# +# lua-prequery-script= + +################################# +# master Act as a master +# +master=yes + +################################# +# max-cache-entries Maximum number of cache entries +# +# max-cache-entries=1000000 + +################################# +# max-ent-entries Maximum number of empty non-terminals in a zone +# +# max-ent-entries=100000 + +################################# +# max-nsec3-iterations Limit the number of NSEC3 hash iterations +# +# max-nsec3-iterations=500 + +################################# +# max-queue-length Maximum queuelength before considering situation lost +# +# max-queue-length=5000 + +################################# +# max-signature-cache-entries Maximum number of signatures cache entries +# +# max-signature-cache-entries= + +################################# +# max-tcp-connections Maximum number of TCP connections +# +# max-tcp-connections=10 + +################################# +# module-dir Default directory for modules +# +# module-dir=/usr/lib/TRIPLET/pdns + +################################# +# negquery-cache-ttl Seconds to store negative query results in the QueryCache +# +# negquery-cache-ttl=60 + +################################# +# no-shuffle Set this to prevent random shuffling of answers - for regression testing +# +# no-shuffle=off + +################################# +# only-notify Only send AXFR NOTIFY to these IP addresses or netmasks +# +# only-notify=0.0.0.0/0,::/0 + +################################# +# out-of-zone-additional-processing Do out of zone additional processing +# +# out-of-zone-additional-processing=yes + +################################# +# overload-queue-length Maximum queuelength moving to packetcache only +# +# overload-queue-length=0 + +################################# +# pipebackend-abi-version Version of the pipe backend ABI +# +# pipebackend-abi-version=1 + +################################# +# prevent-self-notification Don't send notifications to what we think is ourself +# +# prevent-self-notification=yes + +################################# +# query-cache-ttl Seconds to store query results in the QueryCache +# +# query-cache-ttl=20 + +################################# +# query-local-address Source IP address for sending queries +# +# query-local-address=0.0.0.0 + +################################# +# query-local-address6 Source IPv6 address for sending queries +# +# query-local-address6=:: + +################################# +# query-logging Hint backends that queries should be logged +# +# query-logging=no + +################################# +# queue-limit Maximum number of milliseconds to queue a query +# +# queue-limit=1500 + +################################# +# receiver-threads Default number of receiver threads to start +# +# receiver-threads=1 + +################################# +# recursive-cache-ttl Seconds to store packets for recursive queries in the PacketCache +# +# recursive-cache-ttl=10 + +################################# +# recursor If recursion is desired, IP address of a recursing nameserver +# +# recursor=no + +################################# +# retrieval-threads Number of AXFR-retrieval threads for slave operation +# +# retrieval-threads=2 + +################################# +# reuseport Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket +# +# reuseport=no + +################################# +# security-poll-suffix Domain name from which to query security update notifications +# +# security-poll-suffix=secpoll.powerdns.com. + +################################# +# send-root-referral Send out old-fashioned root-referral instead of ServFail in case of no authority +# +# send-root-referral=no + +################################# +# server-id Returned when queried for 'server.id' TXT or NSID, defaults to hostname - disabled or custom +# +# server-id= + +################################# +# setgid If set, change group id to this gid for more security +# +setgid=pdns + +################################# +# setuid If set, change user id to this uid for more security +# +setuid=pdns + +################################# +# signing-threads Default number of signer threads to start +# +# signing-threads=3 + +################################# +# slave Act as a slave +# +# slave=no + +################################# +# slave-cycle-interval Reschedule failed SOA serial checks once every .. seconds +# +# slave-cycle-interval=60 + +################################# +# slave-renotify If we should send out notifications for slaved updates +# +# slave-renotify=no + +################################# +# soa-expire-default Default SOA expire +# +# soa-expire-default=604800 + +################################# +# soa-minimum-ttl Default SOA minimum ttl +# +# soa-minimum-ttl=3600 + +################################# +# soa-refresh-default Default SOA refresh +# +# soa-refresh-default=10800 + +################################# +# soa-retry-default Default SOA retry +# +# soa-retry-default=3600 + +################################# +# socket-dir Where the controlsocket will live +# +# socket-dir=/var/run + +################################# +# tcp-control-address If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-address= + +################################# +# tcp-control-port If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-port=53000 + +################################# +# tcp-control-range If set, remote control of PowerDNS is possible over these networks only +# +# tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 + +################################# +# tcp-control-secret If set, PowerDNS can be controlled over TCP after passing this secret +# +# tcp-control-secret= + +################################# +# traceback-handler Enable the traceback handler (Linux only) +# +# traceback-handler=yes + +################################# +# trusted-notification-proxy IP address of incoming notification proxy +# +# trusted-notification-proxy= + +################################# +# udp-truncation-threshold Maximum UDP response size before we truncate +# +# udp-truncation-threshold=1680 + +################################# +# version-string PowerDNS version in packets - full, anonymous, powerdns or custom +# + +version-string=powerdns +################################# +# webserver Start a webserver for monitoring +# +# webserver=no + +################################# +# webserver-address IP Address of webserver to listen on +# +# webserver-address=127.0.0.1 + +################################# +# webserver-allow-from Webserver access is only allowed from these subnets +# +# webserver-allow-from=0.0.0.0/0,::/0 + +################################# +# webserver-password Password required for accessing the webserver +# +# webserver-password= + +################################# +# webserver-port Port of webserver to listen on +# +# webserver-port=8081 + +################################# +# webserver-print-arguments If the webserver should print arguments +# +# webserver-print-arguments=no + +# include froxlor-bind-specific config +include-dir=/etc/powerdns/froxlor/ +]]> + + + + + + + + + + + + + + +################################# +# allow-dnsupdate-from A global setting to allow DNS updates from these IP ranges. +# +# allow-dnsupdate-from=127.0.0.0/8,::1 + +################################# +# allow-recursion List of subnets that are allowed to recurse +# +allow-recursion=127.0.0.1 + +################################# +# also-notify When notifying a domain, also notify these nameservers +# +# also-notify= + +################################# +# any-to-tcp Answer ANY queries with tc=1, shunting to TCP +# +# any-to-tcp=no + +################################# +# cache-ttl Seconds to store packets in the PacketCache +# +# cache-ttl=20 + +################################# +# carbon-interval Number of seconds between carbon (graphite) updates +# +# carbon-interval=30 + +################################# +# carbon-ourname If set, overrides our reported hostname for carbon stats +# +# carbon-ourname= + +################################# +# carbon-server If set, send metrics in carbon (graphite) format to this server +# +# carbon-server= + +################################# +# chroot If set, chroot to this directory for more security +# +# chroot= + +################################# +# config-dir Location of configuration directory (pdns.conf) +# +config-dir=/etc/powerdns + +################################# +# config-name Name of this virtual configuration - will rename the binary image +# +# config-name= + +################################# +# control-console Debugging switch - don't use +# +# control-console=no + +################################# +# daemon Operate as a daemon +# +daemon=yes + +################################# +# default-ksk-algorithms Default KSK algorithms +# +# default-ksk-algorithms=rsasha256 + +################################# +# default-ksk-size Default KSK size (0 means default) +# +# default-ksk-size=0 + +################################# +# default-soa-mail mail address to insert in the SOA record if none set in the backend +# +# default-soa-mail= + +################################# +# default-soa-name name to insert in the SOA record if none set in the backend +# +# default-soa-name=a.misconfigured.powerdns.server + +################################# +# default-ttl Seconds a result is valid if not set otherwise +# +# default-ttl=3600 + +################################# +# default-zsk-algorithms Default ZSK algorithms +# +# default-zsk-algorithms=rsasha256 + +################################# +# default-zsk-size Default ZSK size (0 means default) +# +# default-zsk-size=0 + +################################# +# direct-dnskey Fetch DNSKEY RRs from backend during DNSKEY synthesis +# +# direct-dnskey=no + +################################# +# disable-axfr Disable zonetransfers but do allow TCP queries +# +# disable-axfr=no + +################################# +# disable-axfr-rectify Disable the rectify step during an outgoing AXFR. Only required for regression testing. +# +# disable-axfr-rectify=no + +################################# +# disable-tcp Do not listen to TCP queries +# +# disable-tcp=no + +################################# +# distributor-threads Default number of Distributor (backend) threads to start +# +# distributor-threads=3 + +################################# +# do-ipv6-additional-processing Do AAAA additional processing +# +# do-ipv6-additional-processing=yes + +################################# +# edns-subnet-processing If we should act on EDNS Subnet options +# +# edns-subnet-processing=no + +################################# +# entropy-source If set, read entropy from this file +# +# entropy-source=/dev/urandom + +################################# +# experimental-api-key REST API Static authentication key (required for API use) +# +# experimental-api-key= + +################################# +# experimental-api-readonly If the JSON API should disallow data modification +# +# experimental-api-readonly=no + +################################# +# experimental-dname-processing If we should support DNAME records +# +# experimental-dname-processing=no + +################################# +# experimental-dnsupdate Enable/Disable DNS update (RFC2136) support. Default is no. +# +# experimental-dnsupdate=no + +################################# +# experimental-json-interface If the webserver should serve JSON data +# +# experimental-json-interface=no + +################################# +# experimental-logfile Filename of the log file for JSON parser +# +# experimental-logfile=/var/log/pdns.log + +################################# +# forward-dnsupdate A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master. +# +# forward-dnsupdate=yes + +################################# +# guardian Run within a guardian process +# +guardian=yes + +################################# +# include-dir Include *.conf files from this directory +# +# include-dir= + +################################# +# launch Which backends to launch and order to query them in +# +# launch= +launch=bind + +################################# +# load-modules Load this module - supply absolute or relative path +# +# load-modules= + +################################# +# local-address Local IP addresses to which we bind +# +local-address=,127.0.0.1 + +################################# +# local-address-nonexist-fail Fail to start if one or more of the local-address's do not exist on this server +# +# local-address-nonexist-fail=yes + +################################# +# local-ipv6 Local IP address to which we bind +# +# local-ipv6= + +################################# +# local-ipv6-nonexist-fail Fail to start if one or more of the local-ipv6 addresses do not exist on this server +# +# local-ipv6-nonexist-fail=yes + +################################# +# local-port The port on which we listen +# +# local-port=53 + +################################# +# log-dns-details If PDNS should log DNS non-erroneous details +# +# log-dns-details=no + +################################# +# log-dns-queries If PDNS should log all incoming DNS queries +# +# log-dns-queries=no + +################################# +# logging-facility Log under a specific facility +# +# logging-facility= + +################################# +# loglevel Amount of logging. Higher is more. Do not set below 3 +# +# loglevel=4 + +################################# +# lua-prequery-script Lua script with prequery handler +# +# lua-prequery-script= + +################################# +# master Act as a master +# +master=yes + +################################# +# max-cache-entries Maximum number of cache entries +# +# max-cache-entries=1000000 + +################################# +# max-ent-entries Maximum number of empty non-terminals in a zone +# +# max-ent-entries=100000 + +################################# +# max-nsec3-iterations Limit the number of NSEC3 hash iterations +# +# max-nsec3-iterations=500 + +################################# +# max-queue-length Maximum queuelength before considering situation lost +# +# max-queue-length=5000 + +################################# +# max-signature-cache-entries Maximum number of signatures cache entries +# +# max-signature-cache-entries= + +################################# +# max-tcp-connections Maximum number of TCP connections +# +# max-tcp-connections=10 + +################################# +# module-dir Default directory for modules +# +# module-dir=/usr/lib/TRIPLET/pdns + +################################# +# negquery-cache-ttl Seconds to store negative query results in the QueryCache +# +# negquery-cache-ttl=60 + +################################# +# no-shuffle Set this to prevent random shuffling of answers - for regression testing +# +# no-shuffle=off + +################################# +# only-notify Only send AXFR NOTIFY to these IP addresses or netmasks +# +# only-notify=0.0.0.0/0,::/0 + +################################# +# out-of-zone-additional-processing Do out of zone additional processing +# +# out-of-zone-additional-processing=yes + +################################# +# overload-queue-length Maximum queuelength moving to packetcache only +# +# overload-queue-length=0 + +################################# +# pipebackend-abi-version Version of the pipe backend ABI +# +# pipebackend-abi-version=1 + +################################# +# prevent-self-notification Don't send notifications to what we think is ourself +# +# prevent-self-notification=yes + +################################# +# query-cache-ttl Seconds to store query results in the QueryCache +# +# query-cache-ttl=20 + +################################# +# query-local-address Source IP address for sending queries +# +# query-local-address=0.0.0.0 + +################################# +# query-local-address6 Source IPv6 address for sending queries +# +# query-local-address6=:: + +################################# +# query-logging Hint backends that queries should be logged +# +# query-logging=no + +################################# +# queue-limit Maximum number of milliseconds to queue a query +# +# queue-limit=1500 + +################################# +# receiver-threads Default number of receiver threads to start +# +# receiver-threads=1 + +################################# +# recursive-cache-ttl Seconds to store packets for recursive queries in the PacketCache +# +# recursive-cache-ttl=10 + +################################# +# recursor If recursion is desired, IP address of a recursing nameserver +# +# recursor=no + +################################# +# retrieval-threads Number of AXFR-retrieval threads for slave operation +# +# retrieval-threads=2 + +################################# +# reuseport Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket +# +# reuseport=no + +################################# +# security-poll-suffix Domain name from which to query security update notifications +# +# security-poll-suffix=secpoll.powerdns.com. + +################################# +# send-root-referral Send out old-fashioned root-referral instead of ServFail in case of no authority +# +# send-root-referral=no + +################################# +# server-id Returned when queried for 'server.id' TXT or NSID, defaults to hostname - disabled or custom +# +# server-id= + +################################# +# setgid If set, change group id to this gid for more security +# +setgid=pdns + +################################# +# setuid If set, change user id to this uid for more security +# +setuid=pdns + +################################# +# signing-threads Default number of signer threads to start +# +# signing-threads=3 + +################################# +# slave Act as a slave +# +# slave=no + +################################# +# slave-cycle-interval Reschedule failed SOA serial checks once every .. seconds +# +# slave-cycle-interval=60 + +################################# +# slave-renotify If we should send out notifications for slaved updates +# +# slave-renotify=no + +################################# +# soa-expire-default Default SOA expire +# +# soa-expire-default=604800 + +################################# +# soa-minimum-ttl Default SOA minimum ttl +# +# soa-minimum-ttl=3600 + +################################# +# soa-refresh-default Default SOA refresh +# +# soa-refresh-default=10800 + +################################# +# soa-retry-default Default SOA retry +# +# soa-retry-default=3600 + +################################# +# socket-dir Where the controlsocket will live +# +# socket-dir=/var/run + +################################# +# tcp-control-address If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-address= + +################################# +# tcp-control-port If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-port=53000 + +################################# +# tcp-control-range If set, remote control of PowerDNS is possible over these networks only +# +# tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 + +################################# +# tcp-control-secret If set, PowerDNS can be controlled over TCP after passing this secret +# +# tcp-control-secret= + +################################# +# traceback-handler Enable the traceback handler (Linux only) +# +# traceback-handler=yes + +################################# +# trusted-notification-proxy IP address of incoming notification proxy +# +# trusted-notification-proxy= + +################################# +# udp-truncation-threshold Maximum UDP response size before we truncate +# +# udp-truncation-threshold=1680 + +################################# +# version-string PowerDNS version in packets - full, anonymous, powerdns or custom +# + +version-string=powerdns +################################# +# webserver Start a webserver for monitoring +# +# webserver=no + +################################# +# webserver-address IP Address of webserver to listen on +# +# webserver-address=127.0.0.1 + +################################# +# webserver-allow-from Webserver access is only allowed from these subnets +# +# webserver-allow-from=0.0.0.0/0,::/0 + +################################# +# webserver-password Password required for accessing the webserver +# +# webserver-password= + +################################# +# webserver-port Port of webserver to listen on +# +# webserver-port=8081 + +################################# +# webserver-print-arguments If the webserver should print arguments +# +# webserver-print-arguments=no + +# include froxlor-bind-specific config +include-dir=/etc/powerdns/froxlor/ +]]> + + + + + named.conf + +# How often to check for zone changes. See 'Operation' section. +bind-check-interval=180 + +# Uncomment to enable Huffman compression on zone data. +# Currently saves around 20% of memory actually used, but slows down operation. +# bind-enable-huffman +]]> + + + + + + + + + + + + {{settings.system.vmail_gid}} + + + + + {{settings.system.vmail_uid}} + + + + + + + + + + + + + + + + + +password = +dbname = +hosts = +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' +]]> + + + + +password = +dbname = +hosts = +query = SELECT domain FROM panel_domains WHERE domain = '%s' AND isemaildomain = '1' AND deactivated = 0 +]]> + + + + +password = +dbname = +expansion_limit = 1 +hosts = +query = SELECT CONCAT(homedir,maildir) FROM mail_users WHERE email = '%s' +]]> + + + + +password = +dbname = +hosts = +query = SELECT DISTINCT username FROM mail_users WHERE email in ((SELECT mail_virtual.email_full FROM mail_virtual WHERE mail_virtual.email = '%s' UNION SELECT mail_virtual.destination FROM mail_virtual WHERE mail_virtual.email = '%s')); +]]> + + + + +password = +dbname = +expansion_limit = 1 +hosts = +query = SELECT uid FROM mail_users WHERE email = '%s' +]]> + + + + +password = +dbname = +expansion_limit = 1 +hosts = +query = SELECT gid FROM mail_users WHERE email = '%s' +]]> + + + + +]]> + + + + + + + + + + + //service[@type='smtp']/general/commands[@index=1] + + //service[@type='smtp']/general/installs[@index=1] + + //service[@type='smtp']/general/commands[@index=2] + + + + +mydestination = $myhostname, localhost.$mydomain, localhost +#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain +#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, +# mail.$mydomain, www.$mydomain, ftp.$mydomain + +# The default setting is 550 (reject mail) but it is safer to start +# with 450 (try again later) until you are certain that your +# local_recipient_maps settings are OK. +# +unknown_local_recipient_reject_code = 550 + +# The mailbox_command parameter specifies the optional external +# command to use instead of mailbox delivery. The command is run as +# the recipient with proper HOME, SHELL and LOGNAME environment settings. +# Exception: delivery for root is done as $default_user. +# +# Other environment variables of interest: USER (recipient username), +# EXTENSION (address extension), DOMAIN (domain part of address), +# and LOCAL (the address localpart). +# +# Unlike other Postfix configuration parameters, the mailbox_command +# parameter is not subjected to $parameter substitutions. This is to +# make it easier to specify shell syntax (see example below). +# +# Avoid shell meta characters because they will force Postfix to run +# an expensive shell process. Procmail alone is expensive enough. +# +# IF YOU USE THIS TO DELIVER MAIL SYSTEM-WIDE, YOU MUST SET UP AN +# ALIAS THAT FORWARDS MAIL FOR ROOT TO A REAL USER. +# +mailbox_command = /usr/lib/dovecot/deliver +#mailbox_command = /usr/bin/procmail -a "$EXTENSION" + +# The debugger_command specifies the external command that is executed +# when a Postfix daemon program is run with the -D option. +# +# Use "command .. & sleep 5" so that the debugger can attach before +# the process marches on. If you use an X-based debugger, be sure to +# set up your XAUTHORITY environment variable before starting Postfix. +# +debugger_command = + PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin + ddd $daemon_directory/$process_name $process_id & sleep 5 + +inet_protocols = ipv4 + +smtpd_helo_required = yes +smtpd_recipient_restrictions = permit_mynetworks, + permit_sasl_authenticated, + reject_unauth_destination, + reject_unauth_pipelining, + reject_non_fqdn_recipient +smtpd_sender_restrictions = permit_mynetworks, + reject_sender_login_mismatch, + permit_sasl_authenticated, + reject_unknown_helo_hostname, + reject_unknown_recipient_domain, + reject_unknown_sender_domain +smtpd_client_restrictions = permit_mynetworks, + permit_sasl_authenticated, + reject_unknown_client_hostname + +# Postfix 2.10 requires this option. Postfix < 2.10 ignores this. +# The option is intentionally left empty. +smtpd_relay_restrictions = + +# Maximum size of Message in bytes (50MB) +message_size_limit = 52428800 + +## SASL Auth Settings +smtpd_sasl_auth_enable = yes +smtpd_sasl_local_domain = $myhostname +broken_sasl_auth_clients = yes +## Dovecot Settings for deliver, SASL Auth and virtual transport +smtpd_sasl_type = dovecot +virtual_transport = dovecot +dovecot_destination_recipient_limit = 1 +smtpd_sasl_path = private/auth + +# Virtual delivery settings +virtual_mailbox_base = / +virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_maps.cf +virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_domains.cf +virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_alias_maps.cf +smtpd_sender_login_maps = proxy:mysql:/etc/postfix/mysql-virtual_sender_permissions.cf +virtual_uid_maps = static: +virtual_gid_maps = static: + +# Local delivery settings +local_transport = local +alias_maps = $alias_database + +# Default Mailbox size, is set to 0 which means unlimited! +mailbox_size_limit = 0 +virtual_mailbox_limit = 0 + +### TLS settings +### +## TLS for outgoing mails from the server to another server +smtp_tls_security_level = may +smtp_tls_note_starttls_offer = yes +## TLS for incoming connections (clients or other mail servers) +smtpd_tls_security_level = may +smtpd_tls_cert_file = +smtpd_tls_key_file = +#smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt +smtpd_tls_loglevel = 1 +smtpd_tls_received_header = yes +smtp_use_tls = yes +smtpd_use_tls = yes +smtpd_tls_session_cache_timeout = 3600s +]]> + + + //service[@type='smtp']/general/files[@index=0] + + + + + //service[@type='smtp']/general/commands[@index=3] + + + + + + + + + + + + + to select which instance is used (an alternative +# to -c ). The instance name is also added to Dovecot processes +# in ps output. +#instance_name = dovecot + +# Greeting message for clients. +#login_greeting = Dovecot ready. + +# Space separated list of trusted network ranges. Connections from these +# IPs are allowed to override their IP addresses and ports (for logging and +# for authentication checks). disable_plaintext_auth is also ignored for +# these networks. Typically you'd specify your IMAP proxy servers here. +#login_trusted_networks = + +# Space separated list of login access check sockets (e.g. tcpwrap) +#login_access_sockets = + +# With proxy_maybe=yes if proxy destination matches any of these IPs, don't do +# proxying. This isn't necessary normally, but may be useful if the destination +# IP is e.g. a load balancer's IP. +#auth_proxy_self = + +# Show more verbose process titles (in ps). Currently shows user name and +# IP address. Useful for seeing who are actually using the IMAP processes +# (eg. shared mailboxes or if same uid is used for multiple accounts). +#verbose_proctitle = no + +# Should all processes be killed when Dovecot master process shuts down. +# Setting this to "no" means that Dovecot can be upgraded without +# forcing existing client connections to close (although that could also be +# a problem if the upgrade is e.g. because of a security fix). +#shutdown_clients = yes + +# If non-zero, run mail commands via this many connections to doveadm server, +# instead of running them directly in the same process. +#doveadm_worker_count = 0 +# UNIX socket or host:port used for connecting to doveadm server +#doveadm_socket_path = doveadm-server + +# Space separated list of environment variables that are preserved on Dovecot +# startup and passed down to all of its child processes. You can also give +# key=value pairs to always set specific settings. +#import_environment = TZ + +## +## Dictionary server settings +## + +# Dictionary can be used to store key=value lists. This is used by several +# plugins. The dictionary can be accessed either directly or though a +# dictionary server. The following dict block maps dictionary names to URIs +# when the server is used. These can then be referenced using URIs in format +# "proxy::". + +dict { + #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext + #expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext +} + +# Most of the actual configuration gets included below. The filenames are +# first sorted by their ASCII value and parsed in that order. The 00-prefixes +# in filenames are intended to make it easier to understand the ordering. +!include conf.d/*.conf + +# A config file can also tried to be included without giving an error if +# it's not found: +!include_try local.conf +]]> + + + + dbname= user= password=" + +# Default password scheme. +# +# List of supported schemes is in +# http://wiki2.dovecot.org/Authentication/PasswordSchemes +# +#default_pass_scheme = CRYPT + +# passdb query to retrieve the password. It can return fields: +# password - The user's password. This field must be returned. +# user - user@domain from the database. Needed with case-insensitive lookups. +# username and domain - An alternative way to represent the "user" field. +# +# The "user" field is often necessary with case-insensitive lookups to avoid +# e.g. "name" and "nAme" logins creating two different mail directories. If +# your user and domain names are in separate fields, you can return "username" +# and "domain" fields instead of "user". +# +# The query can also return other fields which have a special meaning, see +# http://wiki2.dovecot.org/PasswordDatabase/ExtraFields +# +# Commonly used available substitutions (see http://wiki2.dovecot.org/Variables +# for full list): +# %u = entire user@domain +# %n = user part of user@domain +# %d = domain part of user@domain +# +# Note that these can be used only as input to SQL query. If the query outputs +# any of these substitutions, they're not touched. Otherwise it would be +# difficult to have eg. usernames containing '%' characters. +# +# Example: +# password_query = SELECT userid AS user, pw AS password \ +# FROM users WHERE userid = '%u' AND active = 'Y' +# +#password_query = \ +# SELECT username, domain, password \ +# FROM users WHERE username = '%n' AND domain = '%d' + +# userdb query to retrieve the user information. It can return fields: +# uid - System UID (overrides mail_uid setting) +# gid - System GID (overrides mail_gid setting) +# home - Home directory +# mail - Mail location (overrides mail_location setting) +# +# None of these are strictly required. If you use a single UID and GID, and +# home or mail directory fits to a template string, you could use userdb static +# instead. For a list of all fields that can be returned, see +# http://wiki2.dovecot.org/UserDatabase/ExtraFields +# +# Examples: +# user_query = SELECT home, uid, gid FROM users WHERE userid = '%u' +# user_query = SELECT dir AS home, user AS uid, group AS gid FROM users where userid = '%u' +# user_query = SELECT home, 501 AS uid, 501 AS gid FROM users WHERE userid = '%u' +# +#user_query = \ +# SELECT home, uid, gid \ +# FROM users WHERE username = '%n' AND domain = '%d' +user_query = SELECT CONCAT(homedir, maildir) AS home, CONCAT('maildir:', homedir, maildir) AS mail, uid, gid, CONCAT('*:storage=', quota, 'M') as quota_rule FROM mail_users WHERE (username = '%u' OR email = '%u') + +# If you wish to avoid two SQL lookups (passdb + userdb), you can use +# userdb prefetch instead of userdb sql in dovecot.conf. In that case you'll +# also have to return userdb fields in password_query prefixed with "userdb_" +# string. For example: +#password_query = \ +# SELECT userid AS user, password, \ +# home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \ +# FROM users WHERE userid = '%u' +password_query = SELECT username AS user, password_enc AS password, CONCAT(homedir, maildir) AS userdb_home, uid AS userdb_uid, gid AS userdb_gid, CONCAT('maildir:', homedir, maildir) AS userdb_mail, CONCAT('*:storage=', quota, 'M') as userdb_quota_rule FROM mail_users WHERE (username = '%u' OR email = '%u') AND ((imap = 1 AND '%Ls' = 'imap') OR (pop3 = 1 AND '%Ls' = 'pop3') OR ((postfix = 'Y' AND '%Ls' = 'smtp') OR (postfix = 'Y' AND '%Ls' = 'sieve'))) + +# Query to get a list of all usernames. +iterate_query = "SELECT username AS user FROM mail_users WHERE (imap = 1 OR pop3 = 1)" +]]> + + + + to characters. For example "#@/@" means +# that '#' and '/' characters are translated to '@'. +#auth_username_translation = + +# Username formatting before it's looked up from databases. You can use +# the standard variables here, eg. %Lu would lowercase the username, %n would +# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into +# "-AT-". This translation is done after auth_username_translation changes. +#auth_username_format = %Lu + +# If you want to allow master users to log in by specifying the master +# username within the normal username string (ie. not using SASL mechanism's +# support for it), you can specify the separator character here. The format +# is then . UW-IMAP uses "*" as the +# separator, so that could be a good choice. +#auth_master_user_separator = + +# Username to use for users logging in with ANONYMOUS SASL mechanism +#auth_anonymous_username = anonymous + +# Maximum number of dovecot-auth worker processes. They're used to execute +# blocking passdb and userdb queries (eg. MySQL and PAM). They're +# automatically created and destroyed as needed. +#auth_worker_max_count = 30 + +# Host name to use in GSSAPI principal names. The default is to use the +# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab +# entries. +#auth_gssapi_hostname = + +# Kerberos keytab to use for the GSSAPI mechanism. Will use the system +# default (usually /etc/krb5.keytab) if not specified. You may need to change +# the auth service to run as root to be able to read this file. +#auth_krb5_keytab = + +# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and +# ntlm_auth helper. +#auth_use_winbind = no + +# Path for Samba's ntlm_auth helper binary. +#auth_winbind_helper_path = /usr/bin/ntlm_auth + +# Time to delay before replying to failed authentications. +#auth_failure_delay = 2 secs + +# Require a valid SSL client certificate or the authentication fails. +#auth_ssl_require_client_cert = no + +# Take the username from client's SSL certificate, using +# X509_NAME_get_text_by_NID() which returns the subject's DN's +# CommonName. +#auth_ssl_username_from_cert = no + +# Space separated list of wanted authentication mechanisms: +# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey +# gss-spnego +# NOTE: See also disable_plaintext_auth setting. +auth_mechanisms = plain login + +## +## Password and user databases +## + +# +# Password database is used to verify user's password (and nothing more). +# You can have multiple passdbs and userdbs. This is useful if you want to +# allow both system users (/etc/passwd) and virtual users to login without +# duplicating the system users into virtual database. +# +# +# +# User database specifies where mails are located and what user/group IDs +# own them. For single-UID configuration use "static" userdb. +# +# + +#!include auth-deny.conf.ext +#!include auth-master.conf.ext + +#!include auth-system.conf.ext +!include auth-sql.conf.ext +#!include auth-ldap.conf.ext +#!include auth-passwdfile.conf.ext +#!include auth-checkpassword.conf.ext +#!include auth-vpopmail.conf.ext +#!include auth-static.conf.ext +]]> + + + + +# +mail_location = mbox:~/mail:INBOX=/var/mail/%u + +# If you need to set multiple mailbox locations or want to change default +# namespace settings, you can do it by defining namespace sections. +# +# You can have private, shared and public namespaces. Private namespaces +# are for user's personal mails. Shared namespaces are for accessing other +# users' mailboxes that have been shared. Public namespaces are for shared +# mailboxes that are managed by sysadmin. If you create any shared or public +# namespaces you'll typically want to enable ACL plugin also, otherwise all +# users can access all the shared mailboxes, assuming they have permissions +# on filesystem level to do so. +namespace inbox { + # Namespace type: private, shared or public + #type = private + + # Hierarchy separator to use. You should use the same separator for all + # namespaces or some clients get confused. '/' is usually a good one. + # The default however depends on the underlying mail storage format. + #separator = + + # Prefix required to access this namespace. This needs to be different for + # all namespaces. For example "Public/". + #prefix = + + # Physical location of the mailbox. This is in same format as + # mail_location, which is also the default for it. + #location = + + # There can be only one INBOX, and this setting defines which namespace + # has it. + inbox = yes + + # If namespace is hidden, it's not advertised to clients via NAMESPACE + # extension. You'll most likely also want to set list=no. This is mostly + # useful when converting from another server with different namespaces which + # you want to deprecate but still keep working. For example you can create + # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". + #hidden = no + + # Show the mailboxes under this namespace with LIST command. This makes the + # namespace visible for clients that don't support NAMESPACE extension. + # "children" value lists child mailboxes, but hides the namespace prefix. + #list = yes + + # Namespace handles its own subscriptions. If set to "no", the parent + # namespace handles them (empty prefix should always have this as "yes") + #subscriptions = yes +} + +# Example shared namespace configuration +#namespace { + #type = shared + #separator = / + + # Mailboxes are visible under "shared/user@domain/" + # %%n, %%d and %%u are expanded to the destination user. + #prefix = shared/%%u/ + + # Mail location for other users' mailboxes. Note that %variables and ~/ + # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the + # destination user's data. + #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u + + # Use the default namespace for saving subscriptions. + #subscriptions = no + + # List the shared/ namespace only if there are visible shared mailboxes. + #list = children +#} +# Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"? +#mail_shared_explicit_inbox = no + +# System user and group used to access mails. If you use multiple, userdb +# can override these by returning uid or gid fields. You can use either numbers +# or names. +#mail_uid = +#mail_gid = + +# Group to enable temporarily for privileged operations. Currently this is +# used only with INBOX when either its initial creation or dotlocking fails. +# Typically this is set to "mail" to give access to /var/mail. +#mail_privileged_group = + +# Grant access to these supplementary groups for mail processes. Typically +# these are used to set up access to shared mailboxes. Note that it may be +# dangerous to set these if users can create symlinks (e.g. if "mail" group is +# set here, ln -s /var/mail ~/mail/var could allow a user to delete others' +# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it). +mail_access_groups = vmail + +# Allow full filesystem access to clients. There's no access checks other than +# what the operating system does for the active UID/GID. It works with both +# maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/ +# or ~user/. +#mail_full_filesystem_access = no + +# Dictionary for key=value mailbox attributes. Currently used by URLAUTH, but +# soon intended to be used by METADATA as well. +#mail_attribute_dict = + +## +## Mail processes +## + +# Don't use mmap() at all. This is required if you store indexes to shared +# filesystems (NFS or clustered filesystem). +#mmap_disable = no + +# Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL +# since version 3, so this should be safe to use nowadays by default. +#dotlock_use_excl = yes + +# When to use fsync() or fdatasync() calls: +# optimized (default): Whenever necessary to avoid losing important data +# always: Useful with e.g. NFS when write()s are delayed +# never: Never use it (best performance, but crashes can lose data) +#mail_fsync = optimized + +# Locking method for index files. Alternatives are fcntl, flock and dotlock. +# Dotlocking uses some tricks which may create more disk I/O than other locking +# methods. NFS users: flock doesn't work, remember to change mmap_disable. +#lock_method = fcntl + +# Directory in which LDA/LMTP temporarily stores incoming mails >128 kB. +#mail_temp_dir = /tmp + +# Valid UID range for users, defaults to 500 and above. This is mostly +# to make sure that users can't log in as daemons or other system users. +# Note that denying root logins is hardcoded to dovecot binary and can't +# be done even if first_valid_uid is set to 0. +#first_valid_uid = 500 +#last_valid_uid = 0 + +# Valid GID range for users, defaults to non-root/wheel. Users having +# non-valid GID as primary group ID aren't allowed to log in. If user +# belongs to supplementary groups with non-valid GIDs, those groups are +# not set. +#first_valid_gid = 1 +#last_valid_gid = 0 + +# Maximum allowed length for mail keyword name. It's only forced when trying +# to create new keywords. +#mail_max_keyword_length = 50 + +# ':' separated list of directories under which chrooting is allowed for mail +# processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too). +# This setting doesn't affect login_chroot, mail_chroot or auth chroot +# settings. If this setting is empty, "/./" in home dirs are ignored. +# WARNING: Never add directories here which local users can modify, that +# may lead to root exploit. Usually this should be done only if you don't +# allow shell access for users. +#valid_chroot_dirs = + +# Default chroot directory for mail processes. This can be overridden for +# specific users in user database by giving /./ in user's home directory +# (eg. /home/./user chroots into /home). Note that usually there is no real +# need to do chrooting, Dovecot doesn't allow users to access files outside +# their mail directory anyway. If your home directories are prefixed with +# the chroot directory, append "/." to mail_chroot. +#mail_chroot = + +# UNIX socket path to master authentication server to find users. +# This is used by imap (for shared users) and lda. +#auth_socket_path = /var/run/dovecot/auth-userdb + +# Directory where to look up mail plugins. +#mail_plugin_dir = /usr/lib/dovecot/modules + +# Space separated list of plugins to load for all services. Plugins specific to +# IMAP, LDA, etc. are added to this list in their own .conf files. +#mail_plugins = + +## +## Mailbox handling optimizations +## + +# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are +# also required for IMAP NOTIFY extension to be enabled. +#mailbox_list_index = no + +# The minimum number of mails in a mailbox before updates are done to cache +# file. This allows optimizing Dovecot's behavior to do less disk writes at +# the cost of more disk reads. +#mail_cache_min_mail_count = 0 + +# When IDLE command is running, mailbox is checked once in a while to see if +# there are any new mails or other changes. This setting defines the minimum +# time to wait between those checks. Dovecot can also use dnotify, inotify and +# kqueue to find out immediately when changes occur. +#mailbox_idle_check_interval = 30 secs + +# Save mails with CR+LF instead of plain LF. This makes sending those mails +# take less CPU, especially with sendfile() syscall with Linux and FreeBSD. +# But it also creates a bit more disk I/O which may just make it slower. +# Also note that if other software reads the mboxes/maildirs, they may handle +# the extra CRs wrong and cause problems. +#mail_save_crlf = no + +# Max number of mails to keep open and prefetch to memory. This only works with +# some mailbox formats and/or operating systems. +#mail_prefetch_count = 0 + +# How often to scan for stale temporary files and delete them (0 = never). +# These should exist only after Dovecot dies in the middle of saving mails. +#mail_temp_scan_interval = 1w + +## +## Maildir-specific settings +## + +# By default LIST command returns all entries in maildir beginning with a dot. +# Enabling this option makes Dovecot return only entries which are directories. +# This is done by stat()ing each entry, so it causes more disk I/O. +# (For systems setting struct dirent->d_type, this check is free and it's +# done always regardless of this setting) +#maildir_stat_dirs = no + +# When copying a message, do it with hard links whenever possible. This makes +# the performance much better, and it's unlikely to have any side effects. +#maildir_copy_with_hardlinks = yes + +# Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only +# when its mtime changes unexpectedly or when we can't find the mail otherwise. +#maildir_very_dirty_syncs = no + +# If enabled, Dovecot doesn't use the S= in the Maildir filenames for +# getting the mail's physical size, except when recalculating Maildir++ quota. +# This can be useful in systems where a lot of the Maildir filenames have a +# broken size. The performance hit for enabling this is very small. +#maildir_broken_filename_sizes = no + +# Always move mails from new/ directory to cur/, even when the \Recent flags +# aren't being reset. +#maildir_empty_new = no + +## +## mbox-specific settings +## + +# Which locking methods to use for locking mbox. There are four available: +# dotlock: Create .lock file. This is the oldest and most NFS-safe +# solution. If you want to use /var/mail/ like directory, the users +# will need write access to that directory. +# dotlock_try: Same as dotlock, but if it fails because of permissions or +# because there isn't enough disk space, just skip it. +# fcntl : Use this if possible. Works with NFS too if lockd is used. +# flock : May not exist in all systems. Doesn't work with NFS. +# lockf : May not exist in all systems. Doesn't work with NFS. +# +# You can use multiple locking methods; if you do the order they're declared +# in is important to avoid deadlocks if other MTAs/MUAs are using multiple +# locking methods as well. Some operating systems don't allow using some of +# them simultaneously. +# +# The Debian value for mbox_write_locks differs from upstream Dovecot. It is +# changed to be compliant with Debian Policy (section 11.6) for NFS safety. +# Dovecot: mbox_write_locks = dotlock fcntl +# Debian: mbox_write_locks = fcntl dotlock +# +#mbox_read_locks = fcntl +#mbox_write_locks = fcntl dotlock + +# Maximum time to wait for lock (all of them) before aborting. +#mbox_lock_timeout = 5 mins + +# If dotlock exists but the mailbox isn't modified in any way, override the +# lock file after this much time. +#mbox_dotlock_change_timeout = 2 mins + +# When mbox changes unexpectedly we have to fully read it to find out what +# changed. If the mbox is large this can take a long time. Since the change +# is usually just a newly appended mail, it'd be faster to simply read the +# new mails. If this setting is enabled, Dovecot does this but still safely +# fallbacks to re-reading the whole mbox file whenever something in mbox isn't +# how it's expected to be. The only real downside to this setting is that if +# some other MUA changes message flags, Dovecot doesn't notice it immediately. +# Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK +# commands. +#mbox_dirty_syncs = yes + +# Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE, +# EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored. +#mbox_very_dirty_syncs = no + +# Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK +# commands and when closing the mailbox). This is especially useful for POP3 +# where clients often delete all mails. The downside is that our changes +# aren't immediately visible to other MUAs. +#mbox_lazy_writes = yes + +# If mbox size is smaller than this (e.g. 100k), don't write index files. +# If an index file already exists it's still read, just not updated. +#mbox_min_index_size = 0 + +# Mail header selection algorithm to use for MD5 POP3 UIDLs when +# pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired +# algorithm, but it fails if the first Received: header isn't unique in all +# mails. An alternative algorithm is "all" that selects all headers. +#mbox_md5 = apop3d + +## +## mdbox-specific settings +## + +# Maximum dbox file size until it's rotated. +#mdbox_rotate_size = 2M + +# Maximum dbox file age until it's rotated. Typically in days. Day begins +# from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled. +#mdbox_rotate_interval = 0 + +# When creating new mdbox files, immediately preallocate their size to +# mdbox_rotate_size. This setting currently works only in Linux with some +# filesystems (ext4, xfs). +#mdbox_preallocate_space = no + +## +## Mail attachments +## + +# sdbox and mdbox support saving mail attachments to external files, which +# also allows single instance storage for them. Other backends don't support +# this for now. + +# Directory root where to store mail attachments. Disabled, if empty. +#mail_attachment_dir = + +# Attachments smaller than this aren't saved externally. It's also possible to +# write a plugin to disable saving specific attachments externally. +#mail_attachment_min_size = 128k + +# Filesystem backend to use for saving attachments: +# posix : No SiS done by Dovecot (but this might help FS's own deduplication) +# sis posix : SiS with immediate byte-by-byte comparison during saving +# sis-queue posix : SiS with delayed comparison and deduplication +#mail_attachment_fs = sis posix + +# Hash format to use in attachment filenames. You can add any text and +# variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}. +# Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits +#mail_attachment_hash = %{sha1} +]]> + + + + + #service_count = 1 + + # Number of processes to always keep waiting for more connections. + #process_min_avail = 0 + + # If you set service_count=0, you probably need to grow this. + #vsz_limit = $default_vsz_limit +} + +service pop3-login { + inet_listener pop3 { + #port = 110 + } + inet_listener pop3s { + #port = 995 + #ssl = yes + } +} + +service lmtp { + unix_listener lmtp { + #mode = 0666 + } + + # Create inet listener only if you can't use the above UNIX socket + #inet_listener lmtp { + # Avoid making LMTP visible for the entire internet + #address = + #port = + #} +} + +service imap { + # Most of the memory goes to mmap()ing files. You may need to increase this + # limit if you have huge mailboxes. + #vsz_limit = $default_vsz_limit + + # Max. number of IMAP processes (connections) + #process_limit = 1024 +} + +service pop3 { + # Max. number of POP3 processes (connections) + #process_limit = 1024 +} + +service auth { + # auth_socket_path points to this userdb socket by default. It's typically + # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have + # full permissions to this socket are able to get a list of all usernames and + # get the results of everyone's userdb lookups. + # + # The default 0666 mode allows anyone to connect to the socket, but the + # userdb lookups will succeed only if the userdb returns an "uid" field that + # matches the caller process's UID. Also if caller's uid or gid matches the + # socket's uid or gid the lookup succeeds. Anything else causes a failure. + # + # To give the caller full permissions to lookup all users, set the mode to + # something else than 0666 and Dovecot lets the kernel enforce the + # permissions (e.g. 0777 allows everyone full permissions). + unix_listener auth-userdb { + #mode = 0666 + #user = + #group = + } + + # Postfix smtp-auth + unix_listener /var/spool/postfix/private/auth { + mode = 0660 + user = postfix + group = postfix + } + + # Exim4 smtp-auth + unix_listener auth-client { + mode = 0660 + user = mail + # group = Debian-exim + } + + # Auth process is run as this user. + #user = $default_internal_user +} + +service auth-worker { + # Auth worker process is run as root by default, so that it can access + # /etc/shadow. If this isn't necessary, the user should be changed to + # $default_internal_user. + #user = root +} + +service dict { + # If dict proxy is used, mail processes should have access to its socket. + # For example: mode=0660, group=vmail and global mail_access_groups=vmail + unix_listener dict { + #mode = 0600 + #user = + #group = + } +} +]]> + + + + +ssl = yes + +# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before +# dropping root privileges, so keep the key file unreadable by anyone but +# root. Included doc/mkcert.sh can be used to easily generate self-signed +# certificate, just make sure to update the domains in dovecot-openssl.cnf +ssl_cert = < +ssl_key = < + +# If key file is password protected, give the password here. Alternatively +# give it when starting dovecot with -p parameter. Since this file is often +# world-readable, you may want to place this setting instead to a different +# root owned 0600 file by using ssl_key_password = + + + + . %d expands to recipient domain. +postmaster_address = postmaster@ + +# Hostname to use in various parts of sent mails (e.g. in Message-Id) and +# in LMTP replies. Default is the system's real hostname@domain. +#hostname = + +# If user is over quota, return with temporary failure instead of +# bouncing the mail. +#quota_full_tempfail = no + +# Binary to use for sending mails. +#sendmail_path = /usr/sbin/sendmail + +# If non-empty, send mails via this SMTP host[:port] instead of sendmail. +#submission_host = + +# Subject: header to use for rejection mails. You can use the same variables +# as for rejection_reason below. +#rejection_subject = Rejected: %s + +# Human readable error message for rejection mails. You can use variables: +# %n = CRLF, %r = reason, %s = original subject, %t = recipient +#rejection_reason = Your message to <%t> was automatically rejected:%n%r + +# Delimiter character between local-part and detail in email address. +#recipient_delimiter = + + +# Header where the original recipient address (SMTP's RCPT TO: address) is taken +# from if not available elsewhere. With dovecot-lda -a parameter overrides this. +# A commonly used header for this is X-Original-To. +#lda_original_recipient_header = + +# Should saving a mail to a nonexistent mailbox automatically create it? +#lda_mailbox_autocreate = no + +# Should automatically created mailboxes be also automatically subscribed? +#lda_mailbox_autosubscribe = no + +protocol lda { + # Space separated list of plugins to load (default is global mail_plugins). + mail_plugins = $mail_plugins quota sieve +} +]]> + + + + + + + + + #service_count = 1 + + # Number of processes to always keep waiting for more connections. + #process_min_avail = 0 + + # If you set service_count=0, you probably need to grow this. + #vsz_limit = 64M +#} + +#service managesieve { + # Max. number of ManageSieve processes (connections) + #process_limit = 1024 +#} + +# Service configuration + +protocol sieve { + # Maximum ManageSieve command line length in bytes. ManageSieve usually does + # not involve overly long command lines, so this setting will not normally + # need adjustment + #managesieve_max_line_length = 65536 + + # Maximum number of ManageSieve connections allowed for a user from each IP + # address. + # NOTE: The username is compared case-sensitively. + #mail_max_userip_connections = 10 + + # Space separated list of plugins to load (none known to be useful so far). + # Do NOT try to load IMAP plugins here. + #mail_plugins = + + # MANAGESIEVE logout format string: + # %i - total number of bytes read from client + # %o - total number of bytes sent to client + #managesieve_logout_format = bytes=%i/%o + + # To fool ManageSieve clients that are focused on CMU's timesieved you can + # specify the IMPLEMENTATION capability that Dovecot reports to clients. + # For example: 'Cyrus timsieved v2.2.13' + #managesieve_implementation_string = Dovecot Pigeonhole + + # Explicitly specify the SIEVE and NOTIFY capability reported by the server + # before login. If left unassigned these will be reported dynamically + # according to what the Sieve interpreter supports by default (after login + # this may differ depending on the user). + #managesieve_sieve_capability = + #managesieve_notify_capability = + + # The maximum number of compile errors that are returned to the client upon + # script upload or script verification. + #managesieve_max_compile_errors = 5 + + # Refer to 90-sieve.conf for script quota configuration and configuration of + # Sieve execution limits. +} +]]> + + + + = 2.1.4) : %v.%u +# Dovecot v0.99.x : %v.%u +# tpop3d : %Mf +# +# Note that Outlook 2003 seems to have problems with %v.%u format which was +# Dovecot's default, so if you're building a new server it would be a good +# idea to change this. %08Xu%08Xv should be pretty fail-safe. +# +#pop3_uidl_format = %08Xu%08Xv + +# Permanently save UIDLs sent to POP3 clients, so pop3_uidl_format changes +# won't change those UIDLs. Currently this works only with Maildir. +#pop3_save_uidl = no + +# What to do about duplicate UIDLs if they exist? +# allow: Show duplicates to clients. +# rename: Append a temporary -2, -3, etc. counter after the UIDL. +#pop3_uidl_duplicates = allow + +# This option changes POP3 behavior so that it's not possible to actually +# delete mails via POP3, only hide them from future POP3 sessions. The mails +# will still be counted towards user's quota until actually deleted via IMAP. +# Use e.g. "$POP3Deleted" as the value (it will be visible as IMAP keyword). +# Make sure you can legally archive mails before enabling this setting. +#pop3_deleted_flag = + +# POP3 logout format string: +# %i - total number of bytes read from client +# %o - total number of bytes sent to client +# %t - number of TOP commands +# %p - number of bytes sent to client as a result of TOP command +# %r - number of RETR commands +# %b - number of bytes sent to client as a result of RETR command +# %d - number of deleted messages +# %m - number of messages (before deletion) +# %s - mailbox size in bytes (before deletion) +# %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s + +# Workarounds for various client bugs: +# outlook-no-nuls: +# Outlook and Outlook Express hang if mails contain NUL characters. +# This setting replaces them with 0x80 character. +# oe-ns-eoh: +# Outlook Express and Netscape Mail breaks if end of headers-line is +# missing. This option simply sends it if it's missing. +# The list is space-separated. +#pop3_client_workarounds = + +protocol pop3 { + # Space separated list of plugins to load (default is global mail_plugins). + #mail_plugins = $mail_plugins + + # Maximum number of POP3 connections allowed for a user from each IP address. + # NOTE: The username is compared case-sensitively. + #mail_max_userip_connections = 10 +} +]]> + + + + See sieve_before fore executing scripts before the user's personal + # script. + #sieve_default = /var/lib/dovecot/sieve/default.sieve + + # Directory for :personal include scripts for the include extension. This + # is also where the ManageSieve service stores the user's scripts. + sieve_dir = ~/sieve + + # Directory for :global include scripts for the include extension. + #sieve_global_dir = + + # Path to a script file or a directory containing script files that need to be + # executed before the user's script. If the path points to a directory, all + # the Sieve scripts contained therein (with the proper .sieve extension) are + # executed. The order of execution within a directory is determined by the + # file names, using a normal 8bit per-character comparison. Multiple script + # file or directory paths can be specified by appending an increasing number. + #sieve_before = + #sieve_before2 = + #sieve_before3 = (etc...) + + # Identical to sieve_before, only the specified scripts are executed after the + # user's script (only when keep is still in effect!). Multiple script file or + # directory paths can be specified by appending an increasing number. + #sieve_after = + #sieve_after2 = + #sieve_after2 = (etc...) + + # Which Sieve language extensions are available to users. By default, all + # supported extensions are available, except for deprecated extensions or + # those that are still under development. Some system administrators may want + # to disable certain Sieve extensions or enable those that are not available + # by default. This setting can use '+' and '-' to specify differences relative + # to the default. For example `sieve_extensions = +imapflags' will enable the + # deprecated imapflags extension in addition to all extensions were already + # enabled by default. + #sieve_extensions = +notify +imapflags + + # Which Sieve language extensions are ONLY available in global scripts. This + # can be used to restrict the use of certain Sieve extensions to administrator + # control, for instance when these extensions can cause security concerns. + # This setting has higher precedence than the `sieve_extensions' setting + # (above), meaning that the extensions enabled with this setting are never + # available to the user's personal script no matter what is specified for the + # `sieve_extensions' setting. The syntax of this setting is similar to the + # `sieve_extensions' setting, with the difference that extensions are + # enabled or disabled for exclusive use in global scripts. Currently, no + # extensions are marked as such by default. + #sieve_global_extensions = + + # The Pigeonhole Sieve interpreter can have plugins of its own. Using this + # setting, the used plugins can be specified. Check the Dovecot wiki + # (wiki2.dovecot.org) or the pigeonhole website + # (http://pigeonhole.dovecot.org) for available plugins. + # The sieve_extprograms plugin is included in this release. + #sieve_plugins = + + # The separator that is expected between the :user and :detail + # address parts introduced by the subaddress extension. This may + # also be a sequence of characters (e.g. '--'). The current + # implementation looks for the separator from the left of the + # localpart and uses the first one encountered. The :user part is + # left of the separator and the :detail part is right. This setting + # is also used by Dovecot's LMTP service. + #recipient_delimiter = + + + # The maximum size of a Sieve script. The compiler will refuse to compile any + # script larger than this limit. If set to 0, no limit on the script size is + # enforced. + #sieve_max_script_size = 1M + + # The maximum number of actions that can be performed during a single script + # execution. If set to 0, no limit on the total number of actions is enforced. + #sieve_max_actions = 32 + + # The maximum number of redirect actions that can be performed during a single + # script execution. If set to 0, no redirect actions are allowed. + #sieve_max_redirects = 4 + + # The maximum number of personal Sieve scripts a single user can have. If set + # to 0, no limit on the number of scripts is enforced. + # (Currently only relevant for ManageSieve) + #sieve_quota_max_scripts = 0 + + # The maximum amount of disk storage a single user's scripts may occupy. If + # set to 0, no limit on the used amount of disk storage is enforced. + # (Currently only relevant for ManageSieve) + #sieve_quota_max_storage = 0 +} +]]> + + + + + + + + + + + + + + //service[@type='mail']/general/installs[@index=1] + + //service[@type='mail']/general/files[@index=1] + + //service[@type='mail']/general/commands[@index=1] + + + + + + + + + + /dev/null]]> + /etc/apt/sources.list.d/rspamd.list]]> + > /etc/apt/sources.list.d/rspamd.list]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + //service[@type='antispam']/general/commands[@index=1] + + //service[@type='antispam']/general/installs[@index=1] + + //service[@type='antispam']/general/commands[@index=2] + + //service[@type='antispam']/general/files[@index=1] + + //service[@type='antispam']/general/commands[@index=3] + + + + + + + + + + " +[ -f /etc/ssl/certs/proftpd_ec.crt ] || openssl req -new -x509 -nodes -newkey ec:<(openssl ecparam -name secp521r1) -keyout /etc/ssl/private/proftpd_ec.key -out /etc/ssl/certs/proftpd_ec.crt -days 3650 -subj "/C=US/ST=Some-State/O=Internet Widgits Pty Ltd/CN=" +chmod 0600 /etc/ssl/private/proftpd.key /etc/ssl/private/proftpd_ec.key +]]> + + + + + + + + + IdentLookups off + + +ServerName " FTP Server" +ServerType standalone +DeferWelcome off + +DefaultServer on +ShowSymlinks on + +TimeoutNoTransfer 600 +TimeoutStalled 600 +TimeoutIdle 1200 + +DisplayLogin welcome.msg +DisplayChdir .message true +ListOptions "-l" + +DenyFilter \*.*/ + +# Use this to jail all users in their homes +# DefaultRoot ~ + +# Users require a valid shell listed in /etc/shells to login. +# Use this directive to release that constrain. +# RequireValidShell off + +# Port 21 is the standard FTP port. +Port 21 + +# In some cases you have to specify passive ports range to by-pass +# firewall limitations. Ephemeral ports can be used for that, but +# feel free to use a more narrow range. +# PassivePorts 49152 65534 + +# If your host was NATted, this option is useful in order to +# allow passive transfers to work. You have to use your public +# address and opening the passive ports used on your firewall as well. +# MasqueradeAddress 1.2.3.4 + +# This is useful for masquerading address with dynamic IPs: +# refresh any configured MasqueradeAddress directives every 8 hours + +# DynMasqRefresh 28800 + + +# To prevent DoS attacks, set the maximum number of child processes +# to 30. If you need to allow more than 30 concurrent connections +# at once, simply increase this value. Note that this ONLY works +# in standalone mode, in inetd mode you should use an inetd server +# that allows you to limit maximum number of processes per service +# (such as xinetd) +MaxInstances 30 + +# Set the user and group that the server normally runs at. +User proftpd +Group nogroup + +# Umask 022 is a good standard umask to prevent new files and dirs +# (second parm) from being group and world writable. +Umask 022 022 +# Normally, we want files to be overwritable. +AllowOverwrite on + +# Uncomment this if you are using NIS or LDAP via NSS to retrieve passwords: +# PersistentPasswd off + +# This is required to use both PAM-based authentication and local passwords +# AuthOrder mod_auth_pam.c* mod_auth_unix.c + +# Be warned: use of this directive impacts CPU average load! +# Uncomment this if you like to see progress and transfer rate with ftpwho +# in downloads. That is not needed for uploads rates. +# +# UseSendFile off + +TransferLog /var/log/proftpd/xferlog +SystemLog /var/log/proftpd/proftpd.log + +# Logging onto /var/log/lastlog is enabled but set to off by default +#UseLastlog on + +# In order to keep log file dates consistent after chroot, use timezone info +# from /etc/localtime. If this is not set, and proftpd is configured to +# chroot (e.g. DefaultRoot or ), it will use the non-daylight +# savings timezone regardless of whether DST is in effect. +#SetEnv TZ :/etc/localtime + + +QuotaEngine on + + + +Ratios off + + + +# Delay engine reduces impact of the so-called Timing Attack described in +# http://www.securityfocus.com/bid/11430/discuss +# It is on by default. + +DelayEngine on + + + +ControlsEngine off +ControlsMaxClients 2 +ControlsLog /var/log/proftpd/controls.log +ControlsInterval 5 +ControlsSocket /var/run/proftpd/proftpd.sock + + + +AdminControlsEngine off + + +# +# Alternative authentication frameworks +# +#Include /etc/proftpd/ldap.conf +Include /etc/proftpd/sql.conf + +# +# This is used for FTPS connections +# +Include /etc/proftpd/tls.conf + +# +# Useful to keep VirtualHost/VirtualRoot directives separated +# +#Include /etc/proftpd/virtuals.conf + +# A basic anonymous configuration, no upload directories. + +# +# User ftp +# Group nogroup +# # We want clients to be able to login with "anonymous" as well as "ftp" +# UserAlias anonymous ftp +# # Cosmetic changes, all files belongs to ftp user +# DirFakeUser on ftp +# DirFakeGroup on ftp +# +# RequireValidShell off +# +# # Limit the maximum number of anonymous logins +# MaxClients 10 +# +# # We want 'welcome.msg' displayed at login, and '.message' displayed +# # in each newly chdired directory. +# DisplayLogin welcome.msg +# DisplayChdir .message +# +# # Limit WRITE everywhere in the anonymous chroot +# +# +# DenyAll +# +# +# +# # Uncomment this if you're brave. +# # +# # # Umask 022 is a good standard umask to prevent new files and dirs +# # # (second parm) from being group and world writable. +# # Umask 022 022 +# # +# # DenyAll +# # +# # +# # AllowAll +# # +# # +# +# + +# Include other custom configuration files +Include /etc/proftpd/conf.d/ +]]> + + + + + + + + + +DefaultRoot ~ +RequireValidShell off +AuthOrder mod_sql.c + +# +# Choose a SQL backend among MySQL or PostgreSQL. +# Both modules are loaded in default configuration, so you have to specify the backend +# or comment out the unused module in /etc/proftpd/modules.conf. +# Use 'mysql' or 'postgres' as possible values. +# +SQLBackend mysql +# +SQLEngine on +SQLAuthenticate on +# +# Use both an encrypted or plaintext password +SQLAuthTypes Crypt OpenSSL + +SQLAuthenticate users* groups* + +# +# Connection +SQLConnectInfo @ +# +# Describes both users/groups tables +# +SQLUserInfo ftp_users username password uid gid homedir shell +SQLGroupInfo ftp_groups groupname gid members +# +SQLUserWhereClause "login_enabled = 'y'" + +SQLLog PASS login +SQLNamedQuery login UPDATE "last_login=now(), login_count=login_count+1 WHERE username='%u'" ftp_users + +SQLLog RETR download +SQLNamedQuery download UPDATE "down_count=down_count+1, down_bytes=down_bytes+%b WHERE username='%u'" ftp_users + +SQLLog STOR upload +SQLNamedQuery upload UPDATE "up_count=up_count+1, up_bytes=up_bytes+%b WHERE username='%u'" ftp_users + +QuotaEngine on +QuotaShowQuotas on +QuotaDisplayUnits Mb +QuotaLock /var/lock/ftpd.quotatab.lock +QuotaLimitTable sql:/get-quota-limit +QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally +SQLNamedQuery get-quota-limit SELECT "ftp_users.username AS name, ftp_quotalimits.quota_type, ftp_quotalimits.per_session, ftp_quotalimits.limit_type, panel_customers.diskspace*1024 AS bytes_in_avail, ftp_quotalimits.bytes_out_avail, ftp_quotalimits.bytes_xfer_avail, ftp_quotalimits.files_in_avail, ftp_quotalimits.files_out_avail, ftp_quotalimits.files_xfer_avail FROM ftp_users, ftp_quotalimits, panel_customers WHERE ftp_users.username = '%{0}' AND panel_customers.loginname = SUBSTRING_INDEX('%{0}', 'ftp', 1) AND quota_type ='%{1}'" +SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used,bytes_out_used, bytes_xfer_used, files_in_used, files_out_used,files_xfer_used FROM ftp_quotatallies WHERE name = '%{0}' AND quota_type = '%{1}'" +SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used= files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name= '%{6}' AND quota_type = '%{7}'" ftp_quotatallies +SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4},%{5}, %{6}, %{7}" ftp_quotatallies + +]]> + + + + +TLSEngine on +TLSLog /var/log/proftpd/tls.log +TLSProtocol TLSv1.2 TLSv1.3 +TLSRSACertificateFile /etc/ssl/certs/proftpd.crt +TLSRSACertificateKeyFile /etc/ssl/private/proftpd.key +TLSECCertificateFile /etc/ssl/certs/proftpd_ec.crt +TLSECCertificateKeyFile /etc/ssl/private/proftpd_ec.key +# TLSCACertificateFile +TLSOptions NoSessionReuseRequired +TLSVerifyClient off + +# Are clients required to use FTP over TLS when talking to this server? +TLSRequired on + +# Allow SSL/TLS renegotiations when the client requests them, but +# do not force the renegotiations. Some clients do not support +# SSL/TLS renegotiations; when mod_tls forces a renegotiation, these +# clients will close the data connection, or there will be a timeout +# on an idle data connection. +# +#TLSRenegotiate required off + +]]> + + + + +From 127.0.0.1 + + +MaxLoginAttempts 3 + + + BanEngine off + + + BanEngine on + +BanLog /var/log/proftpd/ban.log +BanTable /etc/proftpd/ban.tab +BanMessage "User %u was banned." +BanOnEvent ClientConnectRate 5/00:00:02 12:00:00 "Stop connecting frequently" +BanOnEvent MaxLoginAttempts 3/00:30:00 12:00:00 +BanOnEvent AnonRejectPasswords 1/01:00:00 99:99:99 +BanControlsACLs all allow user root + + + +BanEngine off +DelayEngine off + + ]]> + + + + + + + + + " +openssl dhparam -out /etc/ssl/private/pure-ftpd-dhparams.pem 3072 +chmod 0600 /etc/ssl/private/pure-ftpd.pem /etc/ssl/private/pure-ftpd-dhparams.pem +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Mandatory : user password. You must have a password. + +MYSQLPassword + + +# Mandatory : database to open. + +MYSQLDatabase + + +# Mandatory : how passwords are stored +# Valid values are : "cleartext", "crypt", "sha1", "md5" and "password" +# ("password" = MySQL password() function) +# You can also use "any" to try "crypt", "sha1", "md5" *and* "password" + +MYSQLCrypt any + + +# In the following directives, parts of the strings are replaced at +# run-time before performing queries : +# +# \L is replaced by the login of the user trying to authenticate. +# \I is replaced by the IP address the user connected to. +# \P is replaced by the port number the user connected to. +# \R is replaced by the IP address the user connected from. +# \D is replaced by the remote IP address, as a long decimal number. +# +# Very complex queries can be performed using these substitution strings, +# especially for virtual hosting. + + +# Query to execute in order to fetch the password + +MYSQLGetPW SELECT password FROM ftp_users WHERE username="\L" AND login_enabled="y" + + +# Query to execute in order to fetch the system user name or uid + +MYSQLGetUID SELECT uid FROM ftp_users WHERE username="\L" AND login_enabled="y" + + +# Optional : default UID - if set this overrides MYSQLGetUID + +#MYSQLDefaultUID 1000 + + +# Query to execute in order to fetch the system user group or gid + +MYSQLGetGID SELECT gid FROM ftp_users WHERE username="\L" AND login_enabled="y" + + +# Optional : default GID - if set this overrides MYSQLGetGID + +#MYSQLDefaultGID 1000 + + +# Query to execute in order to fetch the home directory + +MYSQLGetDir SELECT homedir FROM ftp_users WHERE username="\L" AND login_enabled="y" + + +# Optional : query to get the maximal number of files +# Pure-FTPd must have been compiled with virtual quotas support. + +# MySQLGetQTAFS SELECT QuotaFiles FROM users WHERE User='\L' + + +# Optional : query to get the maximal disk usage (virtual quotas) +# The number should be in Megabytes. +# Pure-FTPd must have been compiled with virtual quotas support. + +MySQLGetQTASZ SELECT CASE WHEN panel_customers.diskspace = 0 THEN -1 WHEN panel_customers.diskspace <= -1 THEN 0 ELSE panel_customers.diskspace/1024 END AS QuotaSize FROM panel_customers, ftp_users WHERE username = "\L" AND panel_customers.loginname = SUBSTRING_INDEX('\L', 'ftp', 1) + + +# Optional : ratios. The server has to be compiled with ratio support. + +# MySQLGetRatioUL SELECT ULRatio FROM users WHERE User='\L' +# MySQLGetRatioDL SELECT DLRatio FROM users WHERE User='\L' + + +# Optional : bandwidth throttling. +# The server has to be compiled with throttling support. +# Values are in KB/s . + +# MySQLGetBandwidthUL SELECT ULBandwidth FROM users WHERE User='\L' +# MySQLGetBandwidthDL SELECT DLBandwidth FROM users WHERE User='\L' + +# Enable ~ expansion. NEVER ENABLE THIS BLINDLY UNLESS : +# 1) You know what you are doing. +# 2) Real and virtual users match. + +# MySQLForceTildeExpansion 1 + + +# If you're using a transactionnal storage engine, you can enable SQL +# transactions to avoid races. Leave this commented if you are using the +# traditional MyIsam engine. + +# MySQLTransactions On +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + //service[@type='smtp']/general/commands[@index=3] + + + + + + + *.log { + missingok + daily + rotate 7 + compress + delaycompress + notifempty + create + sharedscripts + postrotate + > /dev/null 2>&1 || true + endscript +} +]]> + + + + + + + + + {{settings.system.mod_fcgid_ownvhost}} + + + + + + + + + + + + + + + {{settings.system.webserver}} + + + + + + {{settings.system.webserver}} + + + + + {{settings.phpfpm.enabled_ownvhost}} + + {{settings.phpfpm.vhost_httpuser}} + + + + + + {{settings.system.webserver}} + + {{settings.phpfpm.enabled_ownvhost}} + + + + + {{settings.system.webserver}} + + + + + + + + + + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> + + + + + + From fce310049a798bb380e99116bb081e16d059ed1c Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 9 May 2024 15:48:23 +0200 Subject: [PATCH 22/33] use Request-wrapper-class for every access to $_POST superglobal Signed-off-by: Michael Kaufmann --- 2fa.php | 9 ++-- admin_admins.php | 10 ++-- admin_apcuinfo.php | 3 +- admin_autoupdate.php | 11 +++-- admin_configfiles.php | 6 +-- admin_cronjobs.php | 4 +- admin_customers.php | 14 +++--- admin_domains.php | 30 ++++++------ admin_index.php | 16 +++---- admin_ipsandports.php | 12 ++--- admin_logger.php | 3 +- admin_message.php | 10 ++-- admin_mysqlserver.php | 10 ++-- admin_opcacheinfo.php | 2 +- admin_phpsettings.php | 22 ++++----- admin_plans.php | 10 ++-- admin_settings.php | 28 +++++------ admin_templates.php | 36 +++++++-------- admin_updates.php | 5 +- api_keys.php | 4 +- customer_domains.php | 16 +++---- customer_email.php | 48 +++++++++---------- customer_extras.php | 32 ++++++------- customer_ftp.php | 12 ++--- customer_index.php | 23 ++++----- customer_mysql.php | 16 +++---- dns_editor.php | 17 +++---- error_report.php | 2 +- index.php | 14 +++--- install/updates/froxlor/update_2.1.inc.php | 5 ++ install/updates/froxlor/update_2.2.inc.php | 2 +- lib/Froxlor/Api/Commands/DomainZones.php | 2 +- lib/Froxlor/Cli/UpdateCommand.php | 1 + lib/Froxlor/Cron/Traffic/ReportsCron.php | 6 +-- lib/Froxlor/PhpHelper.php | 3 ++ lib/Froxlor/Settings/Store.php | 3 +- lib/Froxlor/UI/Request.php | 54 ++++++++++++++-------- lib/Froxlor/Validate/Check.php | 39 ++++++++++++---- lib/configfiles/noble.xml | 2 +- lib/init.php | 2 +- ssl_certificates.php | 2 +- ssl_editor.php | 9 ++-- 42 files changed, 302 insertions(+), 253 deletions(-) diff --git a/2fa.php b/2fa.php index b90cc0d279..635acf313c 100644 --- a/2fa.php +++ b/2fa.php @@ -33,6 +33,7 @@ use Froxlor\FroxlorTwoFactorAuth; use Froxlor\Settings; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\PhpHelper; use Froxlor\User; @@ -63,7 +64,7 @@ ]); Response::standardSuccess('2fa.2fa_removed'); } elseif ($action == 'preadd') { - $type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0'; + $type = Request::post('type_2fa', '0'); $data = ""; if ($type > 0) { @@ -107,9 +108,9 @@ Response::dynamicError('Select one of the possible values for 2FA'); } } elseif ($action == 'add') { - $type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0'; - $data = isset($_POST['data_2fa']) ? $_POST['data_2fa'] : ''; - $code = isset($_POST['codevalidation']) ? $_POST['codevalidation'] : ''; + $type = Request::post('type_2fa', '0'); + $data = Request::post('data_2fa', ''); + $code = Request::post('codevalidation', ''); // validate $result = $tfa->verifyCode($data, $code, 3); diff --git a/admin_admins.php b/admin_admins.php index 98a522f2a1..2399f778d3 100644 --- a/admin_admins.php +++ b/admin_admins.php @@ -106,7 +106,7 @@ Response::standardError('youcantdeleteyourself'); } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { Admins::getLocal($userinfo, [ 'id' => $id ])->delete(); @@ -122,9 +122,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Admins::getLocal($userinfo, $_POST)->add(); + Admins::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -159,9 +159,9 @@ $result = json_decode($json_result, true)['data']; if ($result['loginname'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Admins::getLocal($userinfo, $_POST)->update(); + Admins::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_apcuinfo.php b/admin_apcuinfo.php index f4a7e3408c..f9d96cff92 100644 --- a/admin_apcuinfo.php +++ b/admin_apcuinfo.php @@ -33,6 +33,7 @@ use Froxlor\FroxlorLogger; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\UI\HTML; @@ -42,7 +43,7 @@ $horizontal_bar_size = 950; // 1280px window width if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['change_serversettings'] == '1') { - if ($_POST['send'] == 'send') { + if (Request::post('send') == 'send') { apcu_clear_cache(); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "cleared APCu cache"); header('Location: ' . $linker->getLink([ diff --git a/admin_autoupdate.php b/admin_autoupdate.php index dcaedae881..0c76152be5 100644 --- a/admin_autoupdate.php +++ b/admin_autoupdate.php @@ -32,6 +32,7 @@ use Froxlor\Install\AutoUpdate; use Froxlor\Settings; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; if ($page != 'error') { @@ -110,7 +111,7 @@ } // download the new archive elseif ($page == 'getdownload') { // retrieve the new version from the form - $newversion = isset($_POST['newversion']) ? $_POST['newversion'] : null; + $newversion = Request::post('newversion'); $result = 6; // valid? @@ -130,8 +131,8 @@ ]); } // extract and install new version elseif ($page == 'extract') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { - $toExtract = isset($_POST['archive']) ? $_POST['archive'] : null; + if (Request::post('send') == 'send') { + $toExtract = Request::post('archive'); $localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir()); $result = AutoUpdate::extractZip($localArchive); @@ -145,7 +146,7 @@ // redirect to update-page Response::redirectTo('admin_updates.php'); } else { - $toExtract = isset($_GET['archive']) ? $_GET['archive'] : null; + $toExtract = Request::get('archive'); $localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract); } @@ -192,7 +193,7 @@ } // display error elseif ($page == 'error') { // retrieve error-number via url-parameter - $errno = isset($_GET['errno']) ? (int)$_GET['errno'] : 0; + $errno = Request::get('errno', 0); // 2 = no Zlib // 3 = custom version detected diff --git a/admin_configfiles.php b/admin_configfiles.php index 2de1a5fd1c..51af09720f 100644 --- a/admin_configfiles.php +++ b/admin_configfiles.php @@ -93,14 +93,14 @@ asort($distributions_select); } - if ($distribution != "" && isset($_POST['finish'])) { + if ($distribution != "" && !empty(Request::post('finish'))) { $valid_keys = ['http', 'dns', 'smtp', 'mail', 'antispam', 'ftp', 'system', 'distro']; unset($_POST['finish']); unset($_POST['csrf_token']); - $params = $_POST; + $params = Request::postAll(); $params['distro'] = $distribution; $params['system'] = []; - foreach ($_POST['system'] as $sysdaemon) { + foreach (Request::post('system', []) as $sysdaemon) { $params['system'][] = $sysdaemon; } // validate params diff --git a/admin_cronjobs.php b/admin_cronjobs.php index 3a77e69431..fc4a48d2d8 100644 --- a/admin_cronjobs.php +++ b/admin_cronjobs.php @@ -68,9 +68,9 @@ } $result = json_decode($json_result, true)['data']; if ($result['cronfile'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Cronjobs::getLocal($userinfo, $_POST)->update(); + Cronjobs::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_customers.php b/admin_customers.php index 72062ccaac..2b348d9ee0 100644 --- a/admin_customers.php +++ b/admin_customers.php @@ -119,7 +119,7 @@ } $result = json_decode($json_result, true)['data']; - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { $json_result = Customers::getLocal($userinfo, [ 'id' => $id @@ -147,11 +147,11 @@ } $result = json_decode($json_result, true)['data']; - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { $json_result = Customers::getLocal($userinfo, [ 'id' => $id, - 'delete_userfiles' => (isset($_POST['delete_userfiles']) ? (int)$_POST['delete_userfiles'] : 0) + 'delete_userfiles' => Request::post('delete_userfiles', 0) ])->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); @@ -167,9 +167,9 @@ ], $result['loginname']); } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Customers::getLocal($userinfo, $_POST)->add(); + Customers::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -243,9 +243,9 @@ $result = json_decode($json_result, true)['data']; if ($result['loginname'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Customers::getLocal($userinfo, $_POST)->update(); + Customers::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_domains.php b/admin_domains.php index 1caeb42eeb..722cf21b76 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -100,9 +100,9 @@ ]); if ($result['domain'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send' && $alias_check['count'] == 0) { + if (Request::post('send') == 'send' && $alias_check['count'] == 0) { try { - Domains::getLocal($userinfo, $_POST)->delete(); + Domains::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -121,9 +121,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Domains::getLocal($userinfo, $_POST)->add(); + Domains::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -355,13 +355,13 @@ $usedips[] = $ipsresultrow['id_ipandports']; } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { // remove ssl ip/ports if set is empty - if (!isset($_POST['ssl_ipandport']) || empty($_POST['ssl_ipandport'])) { + if (empty(Request::post('ssl_ipandport'))) { $_POST['remove_ssl_ipandport'] = true; } - Domains::getLocal($userinfo, $_POST)->update(); + Domains::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -572,13 +572,13 @@ } } } elseif ($action == 'jqGetCustomerPHPConfigs') { - $customerid = intval($_POST['customerid']); + $customerid = intval(Request::post('customerid')); $allowed_phpconfigs = Customer::getCustomerDetail($customerid, 'allowed_phpconfigs'); echo !empty($allowed_phpconfigs) ? $allowed_phpconfigs : json_encode([]); exit(); } elseif ($action == 'jqSpeciallogfileNote') { - $domainid = intval($_POST['id']); - $newval = intval($_POST['newval']); + $domainid = intval(Request::post('id')); + $newval = intval(Request::post('newval')); try { $json_result = Domains::getLocal($userinfo, [ 'id' => $domainid @@ -594,9 +594,9 @@ echo 0; exit(); } elseif ($action == 'import') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { - $separator = Validate::validate($_POST['separator'], 'separator'); - $offset = (int)Validate::validate($_POST['offset'], 'offset', "/[0-9]/i"); + if (Request::post('send') == 'send') { + $separator = Validate::validate(Request::post('separator'), 'separator'); + $offset = (int)Validate::validate(Request::post('offset'), 'offset', "/[0-9]/i"); $file_name = $_FILES['file']['tmp_name']; @@ -636,9 +636,9 @@ ]); } } elseif ($action == 'duplicate') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Domains::getLocal($userinfo, $_POST)->duplicate(); + Domains::getLocal($userinfo, Request::postAll())->duplicate(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_index.php b/admin_index.php index 0cca79fa50..8a3b42624f 100644 --- a/admin_index.php +++ b/admin_index.php @@ -201,16 +201,16 @@ $languages = Language::getLanguages(); if (!empty($_POST)) { - if ($_POST['send'] == 'changepassword') { - $old_password = Validate::validate($_POST['old_password'], 'old password'); + if (Request::post('send') == 'changepassword') { + $old_password = Validate::validate(Request::post('old_password'), 'old password'); if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) { Response::standardError('oldpasswordnotcorrect'); } try { - $new_password = Crypt::validatePassword($_POST['new_password'], 'new password'); - $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm'); + $new_password = Crypt::validatePassword(Request::post('new_password'), 'new password'); + $new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm'); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -244,9 +244,9 @@ $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password'); Response::redirectTo($filename); } - } elseif ($_POST['send'] == 'changetheme') { + } elseif (Request::post('send') == 'changetheme') { if (Settings::Get('panel.allow_theme_change_admin') == 1) { - $theme = Validate::validate($_POST['theme'], 'theme'); + $theme = Validate::validate(Request::post('theme'), 'theme'); try { Admins::getLocal($userinfo, [ 'id' => $userinfo['adminid'], @@ -259,8 +259,8 @@ $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'"); } Response::redirectTo($filename); - } elseif ($_POST['send'] == 'changelanguage') { - $def_language = Validate::validate($_POST['def_language'], 'default language'); + } elseif (Request::post('send') == 'changelanguage') { + $def_language = Validate::validate(Request::post('def_language'), 'default language'); if (isset($languages[$def_language])) { try { diff --git a/admin_ipsandports.php b/admin_ipsandports.php index c660bc21c5..905f1348c2 100644 --- a/admin_ipsandports.php +++ b/admin_ipsandports.php @@ -70,7 +70,7 @@ $result = json_decode($json_result, true)['data']; if (isset($result['id']) && $result['id'] == $id) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { IpsAndPorts::getLocal($userinfo, [ 'id' => $id @@ -91,9 +91,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - IpsAndPorts::getLocal($userinfo, $_POST)->add(); + IpsAndPorts::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -119,9 +119,9 @@ $result = json_decode($json_result, true)['data']; if ($result['ip'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - IpsAndPorts::getLocal($userinfo, $_POST)->update(); + IpsAndPorts::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -141,7 +141,7 @@ } } } elseif ($action == 'jqCheckIP') { - $ip = $_POST['ip'] ?? ""; + $ip = Request::post('ip', ''); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) { echo json_encode('
'.lng('error.invalidip', [$ip]).'
'); } elseif (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE)) { diff --git a/admin_logger.php b/admin_logger.php index 28fb963856..334b0c7218 100644 --- a/admin_logger.php +++ b/admin_logger.php @@ -31,6 +31,7 @@ use Froxlor\UI\HTML; use Froxlor\UI\Listing; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; if ($page == 'log' && $userinfo['change_serversettings'] == '1') { @@ -55,7 +56,7 @@ ] ]); } elseif ($action == 'truncate') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { SysLog::getLocal($userinfo, [ 'min_to_keep' => 10 diff --git a/admin_message.php b/admin_message.php index 34343acc88..c5d9913b82 100644 --- a/admin_message.php +++ b/admin_message.php @@ -42,11 +42,11 @@ if ($action == '') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'viewed panel_message'); - if (isset($_POST['send']) && $_POST['send'] == 'send') { - if ($_POST['recipient'] == 0 && $userinfo['customers_see_all'] == '1') { + if (Request::post('send') == 'send') { + if (Request::post('recipient', -1) == 0 && $userinfo['customers_see_all'] == '1') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to admins'); $result = Database::query('SELECT `name`, `email` FROM `' . TABLE_PANEL_ADMINS . "`"); - } elseif ($_POST['recipient'] == 1) { + } elseif (Request::post('recipient', -1) == 1) { if ($userinfo['customers_see_all'] == '1') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to ALL customers'); $result = Database::query('SELECT `firstname`, `name`, `company`, `email` FROM `' . TABLE_PANEL_CUSTOMERS . "`"); @@ -63,8 +63,8 @@ Response::standardError('norecipientsgiven'); } - $subject = $_POST['subject']; - $message = wordwrap($_POST['message'], 70); + $subject = Request::post('subject'); + $message = wordwrap(Request::post('message'), 70); if (!empty($message)) { $mailcounter = 0; diff --git a/admin_mysqlserver.php b/admin_mysqlserver.php index 699a24414c..a213d0803f 100644 --- a/admin_mysqlserver.php +++ b/admin_mysqlserver.php @@ -70,7 +70,7 @@ $result = json_decode($json_result, true)['data']; if (isset($result['id']) && $result['id'] == $id) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { MysqlServer::getLocal($userinfo, [ 'id' => $id @@ -91,9 +91,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - MysqlServer::getLocal($userinfo, $_POST)->add(); + MysqlServer::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -119,9 +119,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['id']) && $result['id'] == $id) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - MysqlServer::getLocal($userinfo, $_POST)->update(); + MysqlServer::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_opcacheinfo.php b/admin_opcacheinfo.php index eddace9e50..443a11d107 100644 --- a/admin_opcacheinfo.php +++ b/admin_opcacheinfo.php @@ -38,7 +38,7 @@ use Froxlor\UI\Response; if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') { - if ($_POST['send'] == 'send') { + if (Request::post('send') == 'send') { opcache_reset(); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "reset OPcache"); header('Location: ' . $linker->getLink([ diff --git a/admin_phpsettings.php b/admin_phpsettings.php index 208692e203..13b14f3605 100644 --- a/admin_phpsettings.php +++ b/admin_phpsettings.php @@ -62,9 +62,9 @@ if ($action == 'add') { if ((int)$userinfo['change_serversettings'] == 1) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - PhpSettings::getLocal($userinfo, $_POST)->add(); + PhpSettings::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -114,7 +114,7 @@ if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { PhpSettings::getLocal($userinfo, [ 'id' => $id @@ -148,9 +148,9 @@ $result = json_decode($json_result, true)['data']; if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - PhpSettings::getLocal($userinfo, $_POST)->update(); + PhpSettings::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -200,9 +200,9 @@ if ($action == 'add') { if ((int)$userinfo['change_serversettings'] == 1) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - FpmDaemons::getLocal($userinfo, $_POST)->add(); + FpmDaemons::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -239,9 +239,9 @@ if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - FpmDaemons::getLocal($userinfo, $_POST)->delete(); + FpmDaemons::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -271,9 +271,9 @@ $result = json_decode($json_result, true)['data']; if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - FpmDaemons::getLocal($userinfo, $_POST)->update(); + FpmDaemons::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_plans.php b/admin_plans.php index f25ccd6f57..0a3bb09756 100644 --- a/admin_plans.php +++ b/admin_plans.php @@ -73,7 +73,7 @@ $result = json_decode($json_result, true)['data']; if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['adminid'] == $result['adminid']) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { HostingPlans::getLocal($userinfo, [ 'id' => $id @@ -96,9 +96,9 @@ Response::standardError('nopermissionsorinvalidid'); } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - HostingPlans::getLocal($userinfo, $_POST)->add(); + HostingPlans::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -176,9 +176,9 @@ } $result['allowed_phpconfigs'] = json_encode($result['allowed_phpconfigs']); - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - HostingPlans::getLocal($userinfo, $_POST)->update(); + HostingPlans::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/admin_settings.php b/admin_settings.php index 8d6fe4974c..057ff9d9fb 100644 --- a/admin_settings.php +++ b/admin_settings.php @@ -47,10 +47,10 @@ $settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/'); Settings::loadSettingsInto($settings_data); - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $_part = isset($_GET['part']) ? $_GET['part'] : ''; if ($_part == '') { - $_part = isset($_POST['part']) ? $_POST['part'] : ''; + $_part = Request::post('part', ''); } if ($_part != '') { @@ -69,12 +69,12 @@ } // check if the session timeout is too low #815 - if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) { + if (Request::post('session_sessiontimeout', 0) < 60) { Response::standardError(['session_timeout', 'session_timeout_desc']); } try { - if (Form::processForm($settings_data, $_POST, [ + if (Form::processForm($settings_data, Request::postAll(), [ 'filename' => $filename, 'action' => $action, 'page' => $page, @@ -99,7 +99,7 @@ } else { $_part = isset($_GET['part']) ? $_GET['part'] : ''; if ($_part == '') { - $_part = isset($_POST['part']) ? $_POST['part'] : ''; + $_part = Request::post('part', ''); } $fields = Form::buildForm($settings_data, $_part); @@ -140,7 +140,7 @@ 'phpinfo' => $phpinfo ]); } elseif ($page == 'rebuildconfigs' && $userinfo['change_serversettings'] == '1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles"); Cronjob::inserttask(TaskId::REBUILD_VHOST); Cronjob::inserttask(TaskId::CREATE_QUOTA); @@ -158,7 +158,7 @@ ]); } } elseif ($page == 'updatecounters' && $userinfo['change_serversettings'] == '1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "updated resource-counters"); $updatecounters = User::updateCounters(true); UI::view('user/resource-counter.html.twig', [ @@ -170,7 +170,7 @@ ]); } } elseif ($page == 'wipecleartextmailpws' && $userinfo['change_serversettings'] == '1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all cleartext mail passwords"); Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = '';"); Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = '0' WHERE `settinggroup` = 'system' AND `varname` = 'mailpwcleartext'"); @@ -181,7 +181,7 @@ ]); } } elseif ($page == 'wipequotas' && $userinfo['change_serversettings'] == '1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all mailquotas"); // Set the quota to 0 which means unlimited @@ -194,7 +194,7 @@ ]); } } elseif ($page == 'enforcequotas' && $userinfo['change_serversettings'] == '1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { // Fetch all accounts $result_stmt = Database::query("SELECT `quota`, `customerid` FROM `" . TABLE_MAIL_USERS . "`"); @@ -233,7 +233,7 @@ } } elseif ($page == 'integritycheck' && $userinfo['change_serversettings'] == '1') { $integrity = new IntegrityCheck(); - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $integrity->fixAll(); } elseif (isset($_GET['action']) && $_GET['action'] == "fix") { HTML::askYesNo('admin_integritycheck_reallyfix', $filename, [ @@ -287,7 +287,7 @@ exit(); } elseif (isset($_GET['action']) && $_GET['action'] == "import") { // import - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { // get uploaded file if (isset($_FILES["import_file"]["tmp_name"])) { $imp_content = file_get_contents($_FILES["import_file"]["tmp_name"]); @@ -330,8 +330,8 @@ $note_type = 'info'; $note_msg = lng('admin.smtptestnote'); - if (isset($_POST['send']) && $_POST['send'] == 'send') { - $test_addr = isset($_POST['test_addr']) ? $_POST['test_addr'] : null; + if (Request::post('send') == 'send') { + $test_addr = Request::post('test_addr'); // Initialize the mailingsystem $testmail = new PHPMailer(true); diff --git a/admin_templates.php b/admin_templates.php index 7ae618bbac..1f535c3f77 100644 --- a/admin_templates.php +++ b/admin_templates.php @@ -192,7 +192,7 @@ $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if ($result['varname'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $del_stmt = Database::prepare(" DELETE FROM `" . TABLE_PANEL_TEMPLATES . "` WHERE `adminid` = :adminid @@ -228,7 +228,7 @@ if (Database::num_rows() > 0) { $row = $result_stmt->fetch(PDO::FETCH_ASSOC); - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $del_stmt = Database::prepare(" DELETE FROM `" . TABLE_PANEL_TEMPLATES . "` WHERE `adminid` = :adminid AND `id` = :id"); @@ -251,13 +251,13 @@ Response::standardError('templatenotfound'); } } elseif ($action == 'add') { - if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') { + if (Request::post('prepare') == 'prepare') { // email templates - $language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); + $language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); if (!array_key_exists($language, $languages)) { Response::standardError('templatelanguageinvalid'); } - $template = Validate::validate($_POST['template'], 'template'); + $template = Validate::validate(Request::post('template'), 'template'); $result_stmt = Database::prepare(" SELECT COUNT(*) as def FROM `" . TABLE_PANEL_TEMPLATES . "` @@ -289,15 +289,15 @@ 'formdata' => $template_add_data['template_add'], 'replacers' => $template_add_data['template_replacers'] ]); - } elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) { + } elseif (Request::post('send') == 'send' && empty(Request::post('filesend'))) { // email templates - $language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); + $language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect')); if (!array_key_exists($language, $languages)) { Response::standardError('templatelanguageinvalid'); } - $template = Validate::validate($_POST['template'], 'template'); - $subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); - $mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); + $template = Validate::validate(Request::post('template'), 'template'); + $subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); + $mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); $templates = []; $result_stmt = Database::prepare(" SELECT `varname` FROM `" . TABLE_PANEL_TEMPLATES . "` @@ -347,10 +347,10 @@ 'page' => $page ]); } - } elseif (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') { + } elseif (Request::post('filesend') == 'filesend') { // file templates - $template = Validate::validate($_POST['template'], 'template'); - $filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); + $template = Validate::validate(Request::post('template'), 'template'); + $filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); $ins_stmt = Database::prepare(" INSERT INTO `" . TABLE_PANEL_TEMPLATES . "` SET @@ -483,9 +483,9 @@ $result = $result_stmt->fetch(PDO::FETCH_ASSOC); if ($result['varname'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { - $subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); - $mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); + if (Request::post('send') == 'send') { + $subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate'); + $mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate'); $upd_stmt = Database::prepare(" UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET @@ -551,8 +551,8 @@ $row = $result_stmt->fetch(PDO::FETCH_ASSOC); // filetemplates - if (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') { - $filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); + if (Request::post('filesend') == 'filesend') { + $filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset'); $upd_stmt = Database::prepare(" UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET `value` = :value diff --git a/admin_updates.php b/admin_updates.php index d2c928aabc..0ae3e08c39 100644 --- a/admin_updates.php +++ b/admin_updates.php @@ -34,6 +34,7 @@ use Froxlor\Settings; use Froxlor\System\Cronjob; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\User; @@ -48,8 +49,8 @@ $successful_update = false; $message = ''; - if (isset($_POST['send']) && $_POST['send'] == 'send') { - if ((isset($_POST['update_preconfig']) && isset($_POST['update_changesagreed']) && intval($_POST['update_changesagreed']) != 0) || !isset($_POST['update_preconfig'])) { + if (Request::post('send') == 'send') { + if ((!empty(Request::post('update_preconfig')) && intval(Request::post('update_changesagreed', 0)) != 0) || empty(Request::post('update_preconfig'))) { include_once Froxlor::getInstallDir() . 'install/updatesql.php'; User::updateCounters(); diff --git a/api_keys.php b/api_keys.php index 1a5660906e..582cdb4b58 100644 --- a/api_keys.php +++ b/api_keys.php @@ -61,7 +61,7 @@ 'section' => 'index', 'page' => $page ]); -} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && $id > 0) { +} elseif (Request::post('send') == 'send' && $action == 'deletesure' && $id > 0) { $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false; if (AREA == 'customer') { $chk_stmt = Database::prepare(" @@ -94,7 +94,7 @@ ]); } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $ins_stmt = Database::prepare(" INSERT INTO `" . TABLE_API_KEYS . "` SET `apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = '' diff --git a/customer_domains.php b/customer_domains.php index e06010a0b2..1fb0533920 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -106,9 +106,9 @@ ]); if (isset($result['parentdomainid']) && $result['parentdomainid'] != '0' && $alias_check['count'] == 0) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - SubDomains::getLocal($userinfo, $_POST)->delete(); + SubDomains::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -127,9 +127,9 @@ } } elseif ($action == 'add') { if ($userinfo['subdomains_used'] < $userinfo['subdomains'] || $userinfo['subdomains'] == '-1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - SubDomains::getLocal($userinfo, $_POST)->add(); + SubDomains::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -248,9 +248,9 @@ Response::standardError('domaincannotbeedited', $result['domain']); } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - SubDomains::getLocal($userinfo, $_POST)->update(); + SubDomains::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -395,8 +395,8 @@ Response::standardError('domains_canteditdomain'); } } elseif ($action == 'jqSpeciallogfileNote') { - $domainid = intval($_POST['id']); - $newval = intval($_POST['newval']); + $domainid = intval(Request::post('id')); + $newval = intval(Request::post('newval')); try { $json_result = SubDomains::getLocal($userinfo, [ 'id' => $domainid diff --git a/customer_email.php b/customer_email.php index 8a5616deef..c3d8e6f55b 100644 --- a/customer_email.php +++ b/customer_email.php @@ -30,6 +30,7 @@ use Froxlor\Api\Commands\EmailDomains; use Froxlor\Api\Commands\EmailForwarders; use Froxlor\Api\Commands\Emails; +use Froxlor\Cron\Mail\Rspamd; use Froxlor\CurrentUser; use Froxlor\Database\Database; use Froxlor\FroxlorLogger; @@ -160,11 +161,11 @@ $result = json_decode($json_result, true)['data']; if (isset($result['email']) && $result['email'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { Emails::getLocal($userinfo, [ 'id' => $id, - 'delete_userfiles' => ($_POST['delete_userfiles'] ?? 0) + 'delete_userfiles' => Request::post('delete_userfiles', 0) ])->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); @@ -187,9 +188,9 @@ } } elseif ($action == 'add') { if ($userinfo['emails_used'] < $userinfo['emails'] || $userinfo['emails'] == '-1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - $json_result = Emails::getLocal($userinfo, $_POST)->add(); + $json_result = Emails::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -244,12 +245,12 @@ $result = json_decode($json_result, true)['data']; if (isset($result['email']) && $result['email'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { Emails::getLocal($userinfo, [ 'id' => $id, - 'spam_tag_level' => $_POST['spam_tag_level'] ?? \Froxlor\Cron\Mail\Rspamd::DEFAULT_MARK_LVL, - 'spam_kill_level' => $_POST['spam_kill_level'] ?? \Froxlor\Cron\Mail\Rspamd::DEFAULT_REJECT_LVL + 'spam_tag_level' => Request::post('spam_tag_level', Rspamd::DEFAULT_MARK_LVL), + 'spam_kill_level' => Request::post('spam_kill_level', Rspamd::DEFAULT_REJECT_LVL) ])->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); @@ -386,9 +387,9 @@ } $result = json_decode($json_result, true)['data']; - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailAccounts::getLocal($userinfo, $_POST)->add(); + EmailAccounts::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -457,9 +458,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['popaccountid']) && $result['popaccountid'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailAccounts::getLocal($userinfo, $_POST)->update(); + EmailAccounts::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -516,9 +517,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['popaccountid']) && $result['popaccountid'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailAccounts::getLocal($userinfo, $_POST)->update(); + EmailAccounts::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -575,9 +576,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['popaccountid']) && $result['popaccountid'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailAccounts::getLocal($userinfo, $_POST)->delete(); + EmailAccounts::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -611,9 +612,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['email']) && $result['email'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailForwarders::getLocal($userinfo, $_POST)->add(); + EmailForwarders::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -673,22 +674,15 @@ $result = json_decode($json_result, true)['data']; if (isset($result['destination']) && $result['destination'] != '') { - if (isset($_POST['forwarderid'])) { - $forwarderid = intval($_POST['forwarderid']); - } elseif (isset($_GET['forwarderid'])) { - $forwarderid = intval($_GET['forwarderid']); - } else { - $forwarderid = 0; - } - + $forwarderid = Request::any('forwarderid', 0); $result['destination'] = explode(' ', $result['destination']); if (isset($result['destination'][$forwarderid]) && $result['email'] != $result['destination'][$forwarderid]) { $forwarder = $result['destination'][$forwarderid]; - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - EmailForwarders::getLocal($userinfo, $_POST)->delete(); + EmailForwarders::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/customer_extras.php b/customer_extras.php index b7e91e334c..16cb4f9d16 100644 --- a/customer_extras.php +++ b/customer_extras.php @@ -97,9 +97,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['username']) && $result['username'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirProtections::getLocal($userinfo, $_POST)->delete(); + DirProtections::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -119,9 +119,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirProtections::getLocal($userinfo, $_POST)->add(); + DirProtections::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -149,9 +149,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['username']) && $result['username'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirProtections::getLocal($userinfo, $_POST)->update(); + DirProtections::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -222,9 +222,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['customerid']) && $result['customerid'] != '' && $result['customerid'] == $userinfo['customerid']) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirOptions::getLocal($userinfo, $_POST)->delete(); + DirOptions::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -240,9 +240,9 @@ } } } elseif ($action == 'add') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirOptions::getLocal($userinfo, $_POST)->add(); + DirOptions::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -271,9 +271,9 @@ $result = json_decode($json_result, true)['data']; if ((isset($result['customerid'])) && ($result['customerid'] != '') && ($result['customerid'] == $userinfo['customerid'])) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DirOptions::getLocal($userinfo, $_POST)->update(); + DirOptions::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -306,10 +306,10 @@ if (Settings::Get('system.exportenabled') == 1) { if ($action == 'abort') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job"); try { - DataDump::getLocal($userinfo, $_POST)->delete(); + DataDump::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -336,9 +336,9 @@ Response::dynamicError($e->getMessage()); } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - DataDump::getLocal($userinfo, $_POST)->add(); + DataDump::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/customer_ftp.php b/customer_ftp.php index 0552140528..234929d5b9 100644 --- a/customer_ftp.php +++ b/customer_ftp.php @@ -87,9 +87,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['username']) && $result['username'] != $userinfo['loginname']) { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Ftps::getLocal($userinfo, $_POST)->delete(); + Ftps::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -108,9 +108,9 @@ } } elseif ($action == 'add') { if ($userinfo['ftps_used'] < $userinfo['ftps'] || $userinfo['ftps'] == '-1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Ftps::getLocal($userinfo, $_POST)->add(); + Ftps::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -164,9 +164,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['username']) && $result['username'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Ftps::getLocal($userinfo, $_POST)->update(); + Ftps::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } diff --git a/customer_index.php b/customer_index.php index 70cb2ae34c..1e3690907e 100644 --- a/customer_index.php +++ b/customer_index.php @@ -38,6 +38,7 @@ use Froxlor\System\Cronjob; use Froxlor\System\Crypt; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\Validate\Validate; @@ -141,16 +142,16 @@ $languages = Language::getLanguages(); if (!empty($_POST)) { - if ($_POST['send'] == 'changepassword') { - $old_password = Validate::validate($_POST['old_password'], 'old password'); + if (Request::post('send') == 'changepassword') { + $old_password = Validate::validate(Request::post('old_password'), 'old password'); if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) { Response::standardError('oldpasswordnotcorrect'); } try { - $new_password = Crypt::validatePassword($_POST['new_password'], 'new password'); - $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm'); + $new_password = Crypt::validatePassword(Request::post('new_password'), 'new password'); + $new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm'); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -185,7 +186,7 @@ $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password'); // Update ftp password - if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') { + if (Request::post('change_main_ftp') == 'true') { $cryptPassword = Crypt::makeCryptPassword($new_password); $stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "` SET `password` = :password @@ -201,7 +202,7 @@ } // Update statistics password - if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') { + if (Request::post('change_stats') == 'true') { $new_stats_password = Crypt::makeCryptPassword($new_password, true); $stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "` @@ -218,7 +219,7 @@ } // Update global myqsl user password - if ($userinfo['mysqls'] != 0 && isset($_POST['change_global_mysql']) && $_POST['change_global_mysql'] == 'true') { + if ($userinfo['mysqls'] != 0 && Request::post('change_global_mysql') == 'true') { $allowed_mysqlservers = json_decode($userinfo['allowed_mysqlserver'] ?? '[]', true); foreach ($allowed_mysqlservers as $dbserver) { // require privileged access for target db-server @@ -235,9 +236,9 @@ Response::redirectTo($filename); } - } elseif ($_POST['send'] == 'changetheme') { + } elseif (Request::post('send') == 'changetheme') { if (Settings::Get('panel.allow_theme_change_customer') == 1) { - $theme = Validate::validate($_POST['theme'], 'theme'); + $theme = Validate::validate(Request::post('theme'), 'theme'); try { Customers::getLocal($userinfo, [ 'id' => $userinfo['customerid'], @@ -250,8 +251,8 @@ $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'"); } Response::redirectTo($filename); - } elseif ($_POST['send'] == 'changelanguage') { - $def_language = Validate::validate($_POST['def_language'], 'default language'); + } elseif (Request::post('send') == 'changelanguage') { + $def_language = Validate::validate(Request::post('def_language'), 'default language'); if (isset($languages[$def_language])) { try { Customers::getLocal($userinfo, [ diff --git a/customer_mysql.php b/customer_mysql.php index df044a640f..b8bdffd0f9 100644 --- a/customer_mysql.php +++ b/customer_mysql.php @@ -123,9 +123,9 @@ $result['dbserver'] = 0; } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Mysqls::getLocal($userinfo, $_POST)->delete(); + Mysqls::getLocal($userinfo, Request::postAll())->delete(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -146,9 +146,9 @@ } } elseif ($action == 'add') { if ($userinfo['mysqls_used'] < $userinfo['mysqls'] || $userinfo['mysqls'] == '-1') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - Mysqls::getLocal($userinfo, $_POST)->add(); + Mysqls::getLocal($userinfo, Request::postAll())->add(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -186,9 +186,9 @@ $result = json_decode($json_result, true)['data']; if (isset($result['databasename']) && $result['databasename'] != '') { - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { try { - $json_result = Mysqls::getLocal($userinfo, $_POST)->update(); + $json_result = Mysqls::getLocal($userinfo, Request::postAll())->update(); } catch (Exception $e) { Response::dynamicError($e->getMessage()); } @@ -223,9 +223,9 @@ Response::dynamicError('No permission'); } - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { - $new_password = Crypt::validatePassword($_POST['mysql_password']); + $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); diff --git a/dns_editor.php b/dns_editor.php index 9d2e41bb2c..6d3d9c5230 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -30,6 +30,7 @@ use Froxlor\Api\Commands\DomainZones; use Froxlor\Dns\Dns; +use Froxlor\Settings; use Froxlor\UI\Collection; use Froxlor\UI\HTML; use Froxlor\UI\Listing; @@ -42,11 +43,11 @@ $domain_id = (int)Request::any('domain_id'); -$record = isset($_POST['dns_record']) ? trim($_POST['dns_record']) : null; -$type = isset($_POST['dns_type']) ? $_POST['dns_type'] : 'A'; -$prio = isset($_POST['dns_mxp']) ? (int)$_POST['dns_mxp'] : null; -$content = isset($_POST['dns_content']) ? trim($_POST['dns_content']) : null; -$ttl = isset($_POST['dns_ttl']) ? (int)$_POST['dns_ttl'] : 18000; +$record = Request::post('dns_record', null); +$type = Request::post('dns_type', 'A'); +$prio = Request::post('dns_mxp'); +$content = Request::post('dns_content'); +$ttl = (int)Request::post('dns_ttl', Settings::get('system.defaultttl')); // get domain-name $domain = Dns::getAllowedDomainEntry($domain_id, AREA, $userinfo); @@ -82,9 +83,9 @@ 'page' => $page, 'domain_id' => $domain_id ]); -} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && !empty($_POST)) { - $entry_id = isset($_POST['id']) ? (int)$_POST['id'] : 0; - $domain_id = isset($_POST['domain_id']) ? (int)$_POST['domain_id'] : 0; +} elseif (Request::post('send') == 'send' && $action == 'deletesure' && !empty($_POST)) { + $entry_id = (int)Request::post('id', 0); + $domain_id = (int)Request::post('domain_id', 0); // remove entry if ($entry_id > 0 && $domain_id > 0) { try { diff --git a/error_report.php b/error_report.php index 0f2347452f..6e0c581378 100644 --- a/error_report.php +++ b/error_report.php @@ -77,7 +77,7 @@ $mail_html = nl2br($mail_body); // send actual report to dev-team - if (isset($_POST['send']) && $_POST['send'] == 'send') { + if (Request::post('send') == 'send') { // send mail and say thanks $_mailerror = false; try { diff --git a/index.php b/index.php index 743bfe7132..34599367cf 100644 --- a/index.php +++ b/index.php @@ -71,7 +71,7 @@ Response::redirectTo('index.php'); exit(); } - $code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null; + $code = Request::post('2fa_code'); // verify entered code $tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname')); // get user-data @@ -162,8 +162,8 @@ exit(); } elseif ($action == 'login') { if (!empty($_POST)) { - $loginname = Validate::validate($_POST['loginname'], 'loginname'); - $password = Validate::validate($_POST['password'], 'password'); + $loginname = Validate::validate(Request::post('loginname'), 'loginname'); + $password = Validate::validate(Request::post('password'), 'password'); $select_additional = ''; if (Settings::Get('panel.db_version') >= 202312230) { @@ -485,8 +485,8 @@ $message = ''; if (!empty($_POST)) { - $loginname = Validate::validate($_POST['loginname'], 'loginname'); - $email = Validate::validateEmail($_POST['loginemail']); + $loginname = Validate::validate(Request::post('loginname'), 'loginname'); + $email = Validate::validateEmail(Request::post('loginemail')); $result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `loginname`= :loginname AND `email`= :email"); @@ -700,8 +700,8 @@ if ($result !== false) { try { - $new_password = Crypt::validatePassword($_POST['new_password'], true); - $new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], true); + $new_password = Crypt::validatePassword(Request::post('new_password'), true); + $new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), true); } catch (Exception $e) { $message = $e->getMessage(); } diff --git a/install/updates/froxlor/update_2.1.inc.php b/install/updates/froxlor/update_2.1.inc.php index 3b982ea0c1..b7b55d5831 100644 --- a/install/updates/froxlor/update_2.1.inc.php +++ b/install/updates/froxlor/update_2.1.inc.php @@ -247,3 +247,8 @@ Update::showUpdateStep("Updating from 2.1.7 to 2.1.8", false); Froxlor::updateToVersion('2.1.8'); } + +if (Froxlor::isFroxlorVersion('2.1.8')) { + Update::showUpdateStep("Updating from 2.1.8 to 2.1.9", false); + Froxlor::updateToVersion('2.1.9'); +} diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index f81f127bfa..a94c714e4a 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -35,7 +35,7 @@ } } -if (Froxlor::isFroxlorVersion('2.1.8')) { +if (Froxlor::isFroxlorVersion('2.1.9')) { Update::showUpdateStep("Enhancing virtual email table"); Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0;"); Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0;"); diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index eebe6b8d06..4a3020a1e2 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -115,7 +115,7 @@ public function add() // validation $errors = []; - if (empty($record)) { + if (empty(trim($record))) { $record = "@"; } diff --git a/lib/Froxlor/Cli/UpdateCommand.php b/lib/Froxlor/Cli/UpdateCommand.php index d7a255eb88..bca38420ef 100644 --- a/lib/Froxlor/Cli/UpdateCommand.php +++ b/lib/Froxlor/Cli/UpdateCommand.php @@ -58,6 +58,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($input->getOption('database')) { $result = $this->validateRequirements($output, true); if ($result == self::SUCCESS) { + require Froxlor::getInstallDir() . '/lib/functions.php'; if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { $output->writeln('' . lng('updates.dbupdate_required') . ''); if ($input->getOption('check-only')) { diff --git a/lib/Froxlor/Cron/Traffic/ReportsCron.php b/lib/Froxlor/Cron/Traffic/ReportsCron.php index 01828c1d7c..cd8babafec 100644 --- a/lib/Froxlor/Cron/Traffic/ReportsCron.php +++ b/lib/Froxlor/Cron/Traffic/ReportsCron.php @@ -211,7 +211,7 @@ public static function run() $_mailerror = false; $mailerr_msg = ""; try { - $mail->SetFrom($row['email'], $row['name']); + $mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname')); $mail->Subject = $mail_subject; $mail->AltBody = $mail_body; $mail->MsgHTML(nl2br($mail_body)); @@ -297,7 +297,7 @@ public static function run() $_mailerror = false; $mailerr_msg = ""; try { - $mail->SetFrom($row['email'], $row['name']); + $mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname')); $mail->Subject = $mail_subject; $mail->Body = $mail_body; $mail->MsgHTML(nl2br($mail_body)); @@ -472,7 +472,7 @@ private static function usageDiskspace() $_mailerror = false; $mailerr_msg = ""; try { - $mail->SetFrom($row['email'], $row['name']); + $mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname')); $mail->Subject = $mail_subject; $mail->AltBody = $mail_body; $mail->MsgHTML(nl2br($mail_body)); diff --git a/lib/Froxlor/PhpHelper.php b/lib/Froxlor/PhpHelper.php index 9a7243e117..77c1899367 100644 --- a/lib/Froxlor/PhpHelper.php +++ b/lib/Froxlor/PhpHelper.php @@ -417,6 +417,9 @@ public static function cleanGlobal(array &$global, AntiXSS &$antiXss) 'admin_pass', 'admin_pass_confirm', 'panel_password_special_char', + 'old_password', + 'new_password', + 'new_password_confirm', ]; if (!empty($global)) { $tmp = $global; diff --git a/lib/Froxlor/Settings/Store.php b/lib/Froxlor/Settings/Store.php index 9b82ca0a99..be5f2cb9c7 100644 --- a/lib/Froxlor/Settings/Store.php +++ b/lib/Froxlor/Settings/Store.php @@ -36,6 +36,7 @@ use Froxlor\Settings; use Froxlor\System\Cronjob; use Froxlor\System\IPTools; +use Froxlor\UI\Request; use Froxlor\Validate\Validate; use PDO; @@ -465,7 +466,7 @@ public static function storeSettingImage($fieldname, $fielddata) } // Delete file? - if ($fielddata['value'] !== "" && array_key_exists($fieldname . '_delete', $_POST) && $_POST[$fieldname . '_delete']) { + if ($fielddata['value'] !== "" && array_key_exists($fieldname . '_delete', $_POST) && Request::post($fieldname . '_delete')) { @unlink(Froxlor::getInstallDir() . '/' . explode('?', $fielddata['value'], 2)[0]); $save_to = ''; } diff --git a/lib/Froxlor/UI/Request.php b/lib/Froxlor/UI/Request.php index e053e8b14b..8817ca93a5 100644 --- a/lib/Froxlor/UI/Request.php +++ b/lib/Froxlor/UI/Request.php @@ -30,14 +30,16 @@ class Request { + private static $cleaned = false; + /** * Get key from current $_GET or $_POST request. * * @param $key - * @param string|null $default + * @param mixed|null $default * @return mixed|string|null */ - public static function any($key, string $default = null) + public static function any($key, $default = null) { self::cleanAll(); @@ -48,10 +50,10 @@ public static function any($key, string $default = null) * Get key from current $_GET request. * * @param $key - * @param string|null $default + * @param mixed|null $default * @return mixed|string|null */ - public static function get($key, string $default = null) + public static function get($key, $default = null) { self::cleanAll(); @@ -62,37 +64,53 @@ public static function get($key, string $default = null) * Get key from current $_POST request. * * @param $key - * @param string|null $default + * @param mixed|null $default * @return mixed|string|null */ - public static function post($key, string $default = null) + public static function post($key, $default = null) { self::cleanAll(); return $_POST[$key] ?? $default; } + /** + * return complete $_POST array + * + * @return array + */ + public static function postAll() + { + self::cleanAll(); + + return $_POST ?? []; + } + /** * Check for xss attempts and clean important globals and * unsetting every variable registered in $_REQUEST and as variable itself */ public static function cleanAll() { - foreach ($_REQUEST as $key => $value) { - if (isset($$key)) { - unset($$key); + if (!self::$cleaned) { + foreach ($_REQUEST as $key => $value) { + if (isset($$key)) { + unset($$key); + } } - } - unset($value); + unset($value); + + $antiXss = new AntiXSS(); - $antiXss = new AntiXSS(); + // check $_GET + PhpHelper::cleanGlobal($_GET, $antiXss); + // check $_POST + PhpHelper::cleanGlobal($_POST, $antiXss); + // check $_COOKIE + PhpHelper::cleanGlobal($_COOKIE, $antiXss); - // check $_GET - PhpHelper::cleanGlobal($_GET, $antiXss); - // check $_POST - PhpHelper::cleanGlobal($_POST, $antiXss); - // check $_COOKIE - PhpHelper::cleanGlobal($_COOKIE, $antiXss); + self::$cleaned = true; + } } /** diff --git a/lib/Froxlor/Validate/Check.php b/lib/Froxlor/Validate/Check.php index 2d5229b15e..70c3c9f509 100644 --- a/lib/Froxlor/Validate/Check.php +++ b/lib/Froxlor/Validate/Check.php @@ -28,6 +28,7 @@ use Froxlor\Database\Database; use Froxlor\FileDir; use Froxlor\Settings; +use Froxlor\UI\Request; class Check { @@ -73,7 +74,7 @@ public static function checkFcgidPhpFpm($fieldname, $fielddata, $newfieldvalue, // interface is to be enabled if ((int)$newfieldvalue == 1) { // check for POST value of the other field == 1 (active) - if (isset($_POST[$check_array[$fieldname]['other_post_field']]) && (int)$_POST[$check_array[$fieldname]['other_post_field']] == 1) { + if ((int)Request::post($check_array[$fieldname]['other_post_field'], 0) == 1) { // the other interface is activated already and STAYS activated if ((int)Settings::Get($check_array[$fieldname]['other_enabled']) == 1) { $returnvalue = [ @@ -83,8 +84,12 @@ public static function checkFcgidPhpFpm($fieldname, $fielddata, $newfieldvalue, } else { // fcgid is being validated before fpm -> "ask" fpm about its state if ($fieldname == 'system_mod_fcgid_enabled') { - $returnvalue = self::checkFcgidPhpFpm('system_phpfpm_enabled', null, - $check_array[$fieldname]['other_post_field'], null); + $returnvalue = self::checkFcgidPhpFpm( + 'system_phpfpm_enabled', + null, + $check_array[$fieldname]['other_post_field'], + null + ); } else { // not, bot are nogo $returnvalue = $returnvalue = [ @@ -117,8 +122,16 @@ public static function checkMysqlAccessHost($fieldname, $fielddata, $newfieldval $mysql_access_host_array = array_unique(array_map('trim', explode(',', $newfieldvalue))); foreach ($mysql_access_host_array as $host_entry) { - if (Validate::validate_ip2($host_entry, true, 'invalidip', true, true, true, true, - false) == false && Validate::validateDomain($host_entry) == false && Validate::validateLocalHostname($host_entry) == false && $host_entry != '%') { + if (Validate::validate_ip2( + $host_entry, + true, + 'invalidip', + true, + true, + true, + true, + false + ) == false && Validate::validateDomain($host_entry) == false && Validate::validateLocalHostname($host_entry) == false && $host_entry != '%') { return [ self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR, 'invalidmysqlhost', @@ -204,8 +217,11 @@ public static function checkPathConflicts($fieldname, $fielddata, $newfieldvalue } // neither dir can be within the other nor can they be equal - if (substr($newdir, 0, strlen($cdir)) == $cdir || substr($cdir, 0, - strlen($newdir)) == $newdir || $newdir == $cdir) { + if (substr($newdir, 0, strlen($cdir)) == $cdir || substr( + $cdir, + 0, + strlen($newdir) + ) == $newdir || $newdir == $cdir) { $returnvalue = [ self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR, 'fcgidpathcannotbeincustomerdoc' @@ -264,8 +280,11 @@ public static function checkUsername($fieldname, $fielddata, $newfieldvalue, $al } $returnvalue = []; - if (Validate::validateUsername($newfieldvalue, Settings::Get('panel.unix_names'), - Database::getSqlUsernameLength() - strlen($allnewfieldvalues['customer_mysqlprefix'])) === true) { + if (Validate::validateUsername( + $newfieldvalue, + Settings::Get('panel.unix_names'), + Database::getSqlUsernameLength() - strlen($allnewfieldvalues['customer_mysqlprefix']) + ) === true) { $returnvalue = [ self::FORMFIELDS_PLAUSIBILITY_CHECK_OK ]; @@ -330,7 +349,7 @@ public static function checkPgpPublicKeySetting($fieldname, $fielddata, $newfiel ]; } // check if the pgp public key is a valid key - putenv('GNUPGHOME='.sys_get_temp_dir()); + putenv('GNUPGHOME=' . sys_get_temp_dir()); if (gnupg_import(gnupg_init(), $newfieldvalue) === false) { return [ self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR, diff --git a/lib/configfiles/noble.xml b/lib/configfiles/noble.xml index 8a583a7c05..479ce504b3 100644 --- a/lib/configfiles/noble.xml +++ b/lib/configfiles/noble.xml @@ -1,6 +1,6 @@ - diff --git a/lib/init.php b/lib/init.php index 4583f68162..c4cc5bdcb9 100644 --- a/lib/init.php +++ b/lib/init.php @@ -361,7 +361,7 @@ UI::twig()->addGlobal('csrf_token', $csrf_token); // check if csrf token is valid if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'PATCH', 'DELETE'])) { - $current_token = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null; + $current_token = Request::post('csrf_token', $_SERVER['HTTP_X_CSRF_TOKEN'] ?? null); if ($current_token != CurrentUser::getField('csrf_token')) { http_response_code(403); Response::dynamicError('CSRF validation failed'); diff --git a/ssl_certificates.php b/ssl_certificates.php index bd917e68db..3b73f3de7a 100644 --- a/ssl_certificates.php +++ b/ssl_certificates.php @@ -55,7 +55,7 @@ 'section' => 'domains', 'page' => $page ]); -} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && $id > 0) { +} elseif (Request::post('send') == 'send' && $action == 'deletesure' && $id > 0) { try { $json_result = Certificates::getLocal($userinfo, [ 'id' => $id diff --git a/ssl_editor.php b/ssl_editor.php index d4b7bab355..b0d1c77051 100644 --- a/ssl_editor.php +++ b/ssl_editor.php @@ -33,6 +33,7 @@ use Froxlor\Database\Database; use Froxlor\PhpHelper; use Froxlor\UI\Panel\UI; +use Froxlor\UI\Request; use Froxlor\UI\Response; // This file is being included in admin_domains and customer_domains @@ -49,13 +50,13 @@ } $result_domain = json_decode($json_result, true)['data']; - if (isset($_POST['send']) && $_POST['send'] == 'send') { - $do_insert = isset($_POST['do_insert']) && ((($_POST['do_insert'] == 1) ? true : false)); + if (Request::post('send') == 'send') { + $do_insert = Request::post('do_insert', 0) == 1; try { if ($do_insert) { - Certificates::getLocal($userinfo, $_POST)->add(); + Certificates::getLocal($userinfo, Request::postAll())->add(); } else { - Certificates::getLocal($userinfo, $_POST)->update(); + Certificates::getLocal($userinfo, Request::postAll())->update(); } } catch (Exception $e) { Response::dynamicError($e->getMessage()); From 793468498223420aec78ae6c3fe7ab34615665f6 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 9 May 2024 16:03:46 +0200 Subject: [PATCH 23/33] use Request-wrapper-class for every access to $_GET superglobal Signed-off-by: Michael Kaufmann --- admin_customers.php | 2 +- admin_index.php | 4 ++-- admin_message.php | 2 +- admin_settings.php | 10 +++++----- admin_templates.php | 2 +- customer_index.php | 2 +- dns_editor.php | 2 +- index.php | 8 ++++---- lib/Froxlor/UI/HTML.php | 24 +++++++++++++++--------- 9 files changed, 31 insertions(+), 25 deletions(-) diff --git a/admin_customers.php b/admin_customers.php index 2b348d9ee0..785145f92e 100644 --- a/admin_customers.php +++ b/admin_customers.php @@ -98,7 +98,7 @@ $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'"); - $target = (isset($_GET['target']) ? $_GET['target'] : 'index'); + $target = Request::get('target', 'index'); $redirect = "customer_" . $target . ".php"; if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) { $redirect = "customer_index.php"; diff --git a/admin_index.php b/admin_index.php index 8a3b42624f..4a2d3d4f18 100644 --- a/admin_index.php +++ b/admin_index.php @@ -55,7 +55,7 @@ $result = $result['switched_user']; session_regenerate_id(true); CurrentUser::setData($result); - $target = (isset($_GET['target']) ? $_GET['target'] : 'index'); + $target = Request::get('target', 'index'); $redirect = "admin_" . $target . ".php"; if (!file_exists(\Froxlor\Froxlor::getInstallDir() . "/" . $redirect)) { $redirect = "admin_index.php"; @@ -111,7 +111,7 @@ $overview['number_domains'] = $number_domains['number_domains']; - if ((isset($_GET['lookfornewversion']) && $_GET['lookfornewversion'] == 'yes') || (isset($lookfornewversion) && $lookfornewversion == 'yes')) { + if (Request::get('lookfornewversion') == 'yes' || (isset($lookfornewversion) && $lookfornewversion == 'yes')) { try { $json_result = Froxlor::getLocal($userinfo)->checkUpdate(); } catch (Exception $e) { diff --git a/admin_message.php b/admin_message.php index c5d9913b82..4482345575 100644 --- a/admin_message.php +++ b/admin_message.php @@ -107,7 +107,7 @@ } } } elseif ($action == 'showsuccess') { - $sentitems = isset($_GET['sentitems']) ? (int)$_GET['sentitems'] : 0; + $sentitems = Request::get('sentitems', 0); if ($sentitems == 0) { $note_type = 'info'; diff --git a/admin_settings.php b/admin_settings.php index 057ff9d9fb..f0c359b3ac 100644 --- a/admin_settings.php +++ b/admin_settings.php @@ -48,7 +48,7 @@ Settings::loadSettingsInto($settings_data); if (Request::post('send') == 'send') { - $_part = isset($_GET['part']) ? $_GET['part'] : ''; + $_part = Request::get('part', ''); if ($_part == '') { $_part = Request::post('part', ''); } @@ -97,7 +97,7 @@ Response::dynamicError($e->getMessage(), $e->getCode()); } } else { - $_part = isset($_GET['part']) ? $_GET['part'] : ''; + $_part = Request::get('part', ''); if ($_part == '') { $_part = Request::post('part', ''); } @@ -235,7 +235,7 @@ $integrity = new IntegrityCheck(); if (Request::post('send') == 'send') { $integrity->fixAll(); - } elseif (isset($_GET['action']) && $_GET['action'] == "fix") { + } elseif (Request::get('action') == "fix") { HTML::askYesNo('admin_integritycheck_reallyfix', $filename, [ 'page' => $page ]); @@ -273,7 +273,7 @@ Response::standardError('jsonextensionnotfound'); } - if (isset($_GET['action']) && $_GET['action'] == "export") { + if (Request::get('action') == "export") { // export try { $json_result = Froxlor::getLocal($userinfo)->exportSettings(); @@ -285,7 +285,7 @@ header('Content-type: application/json'); echo $json_export; exit(); - } elseif (isset($_GET['action']) && $_GET['action'] == "import") { + } elseif (Request::get('action') == "import") { // import if (Request::post('send') == 'send') { // get uploaded file diff --git a/admin_templates.php b/admin_templates.php index 1f535c3f77..07def60c35 100644 --- a/admin_templates.php +++ b/admin_templates.php @@ -371,7 +371,7 @@ Response::redirectTo($filename, [ 'page' => $page ]); - } elseif (!isset($_GET['files'])) { + } elseif (empty(Request::get('files'))) { // email templates $add = false; $language_options = []; diff --git a/customer_index.php b/customer_index.php index 1e3690907e..f052cef6ac 100644 --- a/customer_index.php +++ b/customer_index.php @@ -56,7 +56,7 @@ $result = $result['switched_user']; session_regenerate_id(true); CurrentUser::setData($result); - $target = (isset($_GET['target']) ? $_GET['target'] : 'index'); + $target = Request::get('target', 'index'); $redirect = "admin_" . $target . ".php"; if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) { $redirect = "admin_index.php"; diff --git a/dns_editor.php b/dns_editor.php index 6d3d9c5230..03aaf6a539 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -72,7 +72,7 @@ $errors = str_replace("\n", "
", $e->getMessage()); } } elseif ($action == 'delete') { - $entry_id = isset($_GET['id']) ? (int)$_GET['id'] : 0; + $entry_id = (int)Request::get('id', 0); HTML::askYesNo('dnsentry_reallydelete', $filename, [ 'id' => $entry_id, 'domain_id' => $domain_id, diff --git a/index.php b/index.php index 34599367cf..d36b5ac672 100644 --- a/index.php +++ b/index.php @@ -54,7 +54,7 @@ Response::redirectTo('index.php'); exit(); } - $smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0; + $smessage = (int)Request::get('showmessage', 0); $message = ""; if ($smessage > 0) { $message = lng('error.2fa_wrongcode'); @@ -412,7 +412,7 @@ } exit(); } else { - $smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0; + $smessage = (int)Request::get('showmessage', 0); $message = ''; $successmessage = ''; @@ -683,9 +683,9 @@ "oldest" => time() - 86400 ]); - if (isset($_GET['resetcode']) && strlen($_GET['resetcode']) == 50) { + $activationcode = Request::get('resetcode'); + if (!empty($activationcode) && strlen($activationcode) == 50) { // Check if activation code is valid - $activationcode = $_GET['resetcode']; $timestamp = substr($activationcode, 15, 10); $third = substr($activationcode, 25, 15); $check = substr($activationcode, 40, 10); diff --git a/lib/Froxlor/UI/HTML.php b/lib/Froxlor/UI/HTML.php index 181399b117..d0e878f96d 100644 --- a/lib/Froxlor/UI/HTML.php +++ b/lib/Froxlor/UI/HTML.php @@ -33,10 +33,9 @@ class HTML /** * Build Navigation Sidebar * - * @param - * array navigation data - * @param - * array userinfo the userinfo of the user + * @param array $navigation data + * @param array $userinfo the userinfo of the user + * * @return array the content of the navigation bar according to user-permissions */ public static function buildNavigation(array $navigation, array $userinfo) @@ -44,12 +43,19 @@ public static function buildNavigation(array $navigation, array $userinfo) $returnvalue = []; // sanitize user-given input (url-manipulation) - if (isset($_GET['page']) && is_array($_GET['page'])) { - $_GET['page'] = (string)$_GET['page'][0]; + $req_page = Request::get('page'); + if (!empty($req_page) && is_array($req_page)) { + $req_page = (string)array_shift($req_page); } - if (isset($_GET['action']) && is_array($_GET['action'])) { - $_GET['action'] = (string)$_GET['action'][0]; + // need to preserve this + $_GET['page'] = $req_page; + + $req_action = Request::get('action'); + if (!empty($req_action) && is_array($req_action)) { + $req_action = (string)array_shift($req_action); } + // need to preserve this + $_GET['action'] = $req_action; foreach ($navigation as $box) { if ((!isset($box['show_element']) || $box['show_element'] === true) && (!isset($box['required_resources']) || $box['required_resources'] == '' || (isset($userinfo[$box['required_resources']]) && ((int)$userinfo[$box['required_resources']] > 0 || $userinfo[$box['required_resources']] == '-1')))) { @@ -69,7 +75,7 @@ public static function buildNavigation(array $navigation, array $userinfo) } if ( - ((empty($_GET['page']) && substr_count($element['url'], "page=") == 0) || (isset($_GET['page']) && substr_count($element['url'], "page=" . $_GET['page']) > 0)) + ((empty($req_page) && substr_count($element['url'], "page=") == 0) || (!empty($req_page) && substr_count($element['url'], "page=" . $req_page) > 0)) && substr_count($element['url'], basename($_SERVER["SCRIPT_FILENAME"])) > 0 ) { $active = true; From 9f44b21a045b2438b746f64abf0442b89f40373a Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 10 May 2024 12:37:38 +0200 Subject: [PATCH 24/33] check for global customer mysql user existence when updating password Signed-off-by: Michael Kaufmann --- customer_index.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/customer_index.php b/customer_index.php index f052cef6ac..4a863bc843 100644 --- a/customer_index.php +++ b/customer_index.php @@ -228,7 +228,12 @@ $dbm = new DbManager($log); // 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) { - $dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true); + if ($dbm->getManager()->userExistsOnHost($userinfo['loginname'], $mysql_access_host)) { + $dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true); + } else { + // create global mysql user if not exists + $dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, false, true); + } } $dbm->getManager()->flushPrivileges(); } From cf18140499dccab9725542a652fb03c70b6689ee Mon Sep 17 00:00:00 2001 From: rex2630 Date: Fri, 10 May 2024 17:09:25 +0200 Subject: [PATCH 25/33] Automatic assigment of "worker_processes" in nginx (#1252) * Upgrade of nginx config by default reference --- lib/configfiles/bookworm.xml | 3 ++- lib/configfiles/bullseye.xml | 3 ++- lib/configfiles/focal.xml | 3 ++- lib/configfiles/jammy.xml | 3 ++- lib/configfiles/noble.xml | 5 +++-- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/configfiles/bookworm.xml b/lib/configfiles/bookworm.xml index 72e5ab62a6..754e23b021 100644 --- a/lib/configfiles/bookworm.xml +++ b/lib/configfiles/bookworm.xml @@ -168,8 +168,9 @@ include_shell "/usr/share/lighttpd/include-conf-enabled.pl" - @@ -167,8 +167,9 @@ include_shell "/usr/share/lighttpd/include-conf-enabled.pl" Date: Fri, 10 May 2024 17:23:25 +0200 Subject: [PATCH 26/33] never allow {{ }} in user-input --- lib/Froxlor/UI/Request.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Froxlor/UI/Request.php b/lib/Froxlor/UI/Request.php index 8817ca93a5..4e5016548f 100644 --- a/lib/Froxlor/UI/Request.php +++ b/lib/Froxlor/UI/Request.php @@ -101,6 +101,9 @@ public static function cleanAll() unset($value); $antiXss = new AntiXSS(); + $antiXss->addNeverAllowedRegex([ + '{{(.*)}}' => '' + ]); // check $_GET PhpHelper::cleanGlobal($_GET, $antiXss); From 0d86340a4c5661691bb05e210c669224436fbac7 Mon Sep 17 00:00:00 2001 From: envoyr Date: Sat, 11 May 2024 18:38:56 +0200 Subject: [PATCH 27/33] fix session_sessiontimeout request and add missing language string Signed-off-by: envoyr --- admin_settings.php | 2 +- dns_editor.php | 2 +- lng/de.lng.php | 1 + lng/en.lng.php | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/admin_settings.php b/admin_settings.php index f0c359b3ac..9983b6b3b1 100644 --- a/admin_settings.php +++ b/admin_settings.php @@ -69,7 +69,7 @@ } // check if the session timeout is too low #815 - if (Request::post('session_sessiontimeout', 0) < 60) { + if (!empty(Request::post('session_sessiontimeout')) && intval(Request::post('session_sessiontimeout', 0)) < 60) { Response::standardError(['session_timeout', 'session_timeout_desc']); } diff --git a/dns_editor.php b/dns_editor.php index 03aaf6a539..ee03f6dca3 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -43,7 +43,7 @@ $domain_id = (int)Request::any('domain_id'); -$record = Request::post('dns_record', null); +$record = Request::post('dns_record'); $type = Request::post('dns_type', 'A'); $prio = Request::post('dns_mxp'); $content = Request::post('dns_content'); diff --git a/lng/de.lng.php b/lng/de.lng.php index 104a95fa85..aab6b73bff 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -1830,6 +1830,7 @@ ], 'passwordcryptfunc' => [ 'title' => 'Wählen Sie die zu verwendende Passwort-Verschlüsselungsmethode', + 'description' => 'Wählen Sie, welche Methode zur Verschlüsselung von Kennwörtern verwendet werden soll. Wenn Sie diese Einstellung ändern, werden nur neue Kennwörter mit der neuen Methode verschlüsselt. Bestehende Passwörter werden nicht geändert.' ], 'systemdefault' => 'Systemstandard', 'panel_allow_theme_change_admin' => 'Erlaube Admins das Theme zu wechseln', diff --git a/lng/en.lng.php b/lng/en.lng.php index ba2c765331..e24ed0bd3a 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -1952,6 +1952,7 @@ ], 'passwordcryptfunc' => [ 'title' => 'Choose which password-crypt method is to be used', + 'description' => 'Choose which password-crypt method is to be used. If you change this setting, only new passwords will be encrypted with the new method. Existing passwords will not be changed.', ], 'systemdefault' => 'System default', 'panel_allow_theme_change_admin' => 'Allow admins to change the theme', From 73182a6909dfb0a3ea3e8ca4cc08dadc245a2c31 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 May 2024 11:09:48 +0200 Subject: [PATCH 28/33] check for already existing symlink to bin/froxlor-cli; remove some very old dkim related settings Signed-off-by: Michael Kaufmann --- install/updates/froxlor/update_2.2.inc.php | 4 ++++ lib/configfiles/bookworm.xml | 2 +- lib/configfiles/bullseye.xml | 2 +- lib/configfiles/focal.xml | 2 +- lib/configfiles/jammy.xml | 2 +- lib/configfiles/noble.xml | 4 +++- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index a94c714e4a..bd10288993 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -55,6 +55,10 @@ Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_domains';"); Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_algorithm';"); Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_notes';"); + Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsp';"); + Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_dkimkeys';"); + Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_servicetype';"); + Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsppolicy';"); Update::lastStepStatus(0); if ($antispam_activated) { diff --git a/lib/configfiles/bookworm.xml b/lib/configfiles/bookworm.xml index 754e23b021..e00236bd0e 100644 --- a/lib/configfiles/bookworm.xml +++ b/lib/configfiles/bookworm.xml @@ -3499,7 +3499,7 @@ aliases: files - bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/bullseye.xml b/lib/configfiles/bullseye.xml index addfb8d39b..aaedc027da 100644 --- a/lib/configfiles/bullseye.xml +++ b/lib/configfiles/bullseye.xml @@ -5062,7 +5062,7 @@ aliases: files - bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/focal.xml b/lib/configfiles/focal.xml index 56838f43cf..dfda6e05da 100644 --- a/lib/configfiles/focal.xml +++ b/lib/configfiles/focal.xml @@ -4289,7 +4289,7 @@ aliases: files - bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/jammy.xml b/lib/configfiles/jammy.xml index cfa0b6e517..e1f5dab71f 100644 --- a/lib/configfiles/jammy.xml +++ b/lib/configfiles/jammy.xml @@ -4286,7 +4286,7 @@ aliases: files - bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/noble.xml b/lib/configfiles/noble.xml index e25771c6c3..85039e4d54 100644 --- a/lib/configfiles/noble.xml +++ b/lib/configfiles/noble.xml @@ -3678,6 +3678,8 @@ ModuleControlsACLs lsmod allow user * LoadModule mod_ctrls_admin.c LoadModule mod_tls.c +LoadModule mod_ident.c + # Install one of proftpd-mod-mysql, proftpd-mod-pgsql or any other # SQL backend engine to use this module and the required backend. # This module must be mandatory loaded before anyone of @@ -4286,7 +4288,7 @@ aliases: files - bin/froxlor-cli /usr/local/bin/froxlor-cli]]> + bin/froxlor-cli /usr/local/bin/froxlor-cli]]> bin/froxlor-cli froxlor:cron --run-task 99]]> From cda0b3116fd19646aae73f5da155ee0abc292d7b Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 May 2024 13:51:03 +0200 Subject: [PATCH 29/33] make docs url dynamic based on (night/testing) version Signed-off-by: Michael Kaufmann --- customer_domains.php | 2 +- customer_email.php | 4 ++-- customer_extras.php | 6 +++--- customer_ftp.php | 2 +- customer_mysql.php | 2 +- lib/Froxlor/Froxlor.php | 20 +++++++++++++++++++- lib/navigation/00.froxlor.main.php | 8 ++++---- 7 files changed, 31 insertions(+), 13 deletions(-) diff --git a/customer_domains.php b/customer_domains.php index 1fb0533920..c87105c0fc 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -72,7 +72,7 @@ } $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/domains/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/domains/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' diff --git a/customer_email.php b/customer_email.php index c3d8e6f55b..dc55aed083 100644 --- a/customer_email.php +++ b/customer_email.php @@ -77,7 +77,7 @@ } $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/emails/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' @@ -139,7 +139,7 @@ ]; } $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/emails/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' diff --git a/customer_extras.php b/customer_extras.php index 16cb4f9d16..0656241d8d 100644 --- a/customer_extras.php +++ b/customer_extras.php @@ -75,7 +75,7 @@ ]; $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' @@ -200,7 +200,7 @@ ]; $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' @@ -349,7 +349,7 @@ $actions_links = [ [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' diff --git a/customer_ftp.php b/customer_ftp.php index 234929d5b9..05e169237a 100644 --- a/customer_ftp.php +++ b/customer_ftp.php @@ -65,7 +65,7 @@ ]; } $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/ftp-accounts/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/ftp-accounts/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' diff --git a/customer_mysql.php b/customer_mysql.php index b8bdffd0f9..e2372448a8 100644 --- a/customer_mysql.php +++ b/customer_mysql.php @@ -89,7 +89,7 @@ } $actions_links[] = [ - 'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/databases/', + 'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/databases/', 'target' => '_blank', 'icon' => 'fa-solid fa-circle-info', 'class' => 'btn-outline-secondary' diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index dcebc533a4..87ccc013e9 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -39,7 +39,7 @@ final class Froxlor // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; - const DOCS_URL = 'https://docs.froxlor.org/v2.2/'; + const DOCS_URL = 'https://docs.froxlor.org'; /** * return path to where froxlor is installed, e.g. @@ -52,6 +52,14 @@ public static function getInstallDir(): string return dirname(__DIR__, 2) . '/'; } + public static function getDocsUrl(): string + { + if (preg_match('/(.+)-(dev|beta|rc)\d+$/', self::VERSION)) { + return self::DOCS_URL . '/dev/'; + } + return self::DOCS_URL . '/v' . self::getShortVersion() . '/'; + } + /** * return basic version * @@ -62,6 +70,16 @@ public static function getVersion(): string return self::VERSION; } + /** + * return short basic version + * + * @return string + */ + public static function getShortVersion(): string + { + return explode(".", self::VERSION)[0] . '.' . explode(".", self::VERSION)[1]; + } + /** * return version + branding and database-version * diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index 08b635839b..5e7d3230fb 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -161,13 +161,13 @@ 'show_element' => (!Settings::IsInList('panel.customer_hide_options', 'misc.documentation')), 'elements' => [ [ - 'url' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/', + 'url' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/', 'label' => lng('admin.userguide'), 'new_window' => true, 'is_external' => true, ], [ - 'url' => \Froxlor\Froxlor::DOCS_URL . 'api-guide/', + 'url' => \Froxlor\Froxlor::getDocsUrl() . 'api-guide/', 'label' => lng('admin.apiguide'), 'new_window' => true, 'show_element' => Settings::Get('api.enabled') == 1 && CurrentUser::getField('api_allowed') == 1, @@ -348,13 +348,13 @@ 'icon' => 'fa-solid fa-circle-info', 'elements' => [ [ - 'url' => \Froxlor\Froxlor::DOCS_URL . 'admin-guide/', + 'url' => \Froxlor\Froxlor::getDocsUrl() . 'admin-guide/', 'label' => lng('admin.adminguide'), 'new_window' => true, 'is_external' => true, ], [ - 'url' => \Froxlor\Froxlor::DOCS_URL . 'api-guide/', + 'url' => \Froxlor\Froxlor::getDocsUrl() . 'api-guide/', 'label' => lng('admin.apiguide'), 'new_window' => true, 'show_element' => Settings::Get('api.enabled') == 1, From 597f338353f1667a62c45c9a6f2049a700b5856e Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 May 2024 14:15:05 +0200 Subject: [PATCH 30/33] add force-updatecheck renew icon for update-check popover Signed-off-by: Michael Kaufmann --- lib/Froxlor/Ajax/Ajax.php | 3 ++- templates/Froxlor/assets/js/jquery/updatecheck.js | 11 ++++++++++- templates/Froxlor/assets/scss/_variables.scss | 3 +++ templates/Froxlor/misc/version_popover.html.twig | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/Froxlor/Ajax/Ajax.php b/lib/Froxlor/Ajax/Ajax.php index fc14738934..1a1ae2e5d0 100644 --- a/lib/Froxlor/Ajax/Ajax.php +++ b/lib/Froxlor/Ajax/Ajax.php @@ -193,7 +193,8 @@ private function getUpdateCheck() UI::initTwig(); try { - $json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo)->checkUpdate(); + $force = Request::get('force', 0); + $json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo, ['force' => $force])->checkUpdate(); $result = json_decode($json_result, true)['data']; $result['full_version'] = Froxlor::getFullVersion(); $result['dbversion'] = Froxlor::DBVERSION; diff --git a/templates/Froxlor/assets/js/jquery/updatecheck.js b/templates/Froxlor/assets/js/jquery/updatecheck.js index dcc5ef4096..1a8d686a34 100644 --- a/templates/Froxlor/assets/js/jquery/updatecheck.js +++ b/templates/Froxlor/assets/js/jquery/updatecheck.js @@ -4,8 +4,17 @@ export default function () { * updatecheck */ if (document.getElementById('updatecheck')) { + runCheck(); + } + + $('#forceUpdateCheck').on('click', function () { + runCheck(1); + }); + + function runCheck(force = 0) + { $.ajax({ - url: "lib/ajax.php?action=updatecheck&theme=" + window.$theme, + url: "lib/ajax.php?action=updatecheck&theme=" + window.$theme + "&force=" + force, type: "GET", success: function (data) { $("#updatecheck").html(data); diff --git a/templates/Froxlor/assets/scss/_variables.scss b/templates/Froxlor/assets/scss/_variables.scss index 8e1bef65e2..08a97dbf2d 100644 --- a/templates/Froxlor/assets/scss/_variables.scss +++ b/templates/Froxlor/assets/scss/_variables.scss @@ -86,3 +86,6 @@ $heading-border-color-dark: rgba(0,0,0,0.15); // Search $search-bg: $navbar-bg; + +// Popover size +$popover-max-width: 320px; diff --git a/templates/Froxlor/misc/version_popover.html.twig b/templates/Froxlor/misc/version_popover.html.twig index 554bc0ebfd..5f1c706b51 100644 --- a/templates/Froxlor/misc/version_popover.html.twig +++ b/templates/Froxlor/misc/version_popover.html.twig @@ -26,4 +26,7 @@ {{ call_static('\\Froxlor\\Froxlor', 'getInstallDir') }}bin/froxlor-cli froxlor:update {% endif %} {% endif %} +
+ +
{% endmacro %} From a602865feea26835f86b54a576b8c8290542b376 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 May 2024 14:56:47 +0200 Subject: [PATCH 31/33] fix force version re-check button Signed-off-by: Michael Kaufmann --- templates/Froxlor/assets/js/jquery/updatecheck.js | 13 ++++++++----- templates/Froxlor/misc/version_popover.html.twig | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/templates/Froxlor/assets/js/jquery/updatecheck.js b/templates/Froxlor/assets/js/jquery/updatecheck.js index 1a8d686a34..45cfdbe28b 100644 --- a/templates/Froxlor/assets/js/jquery/updatecheck.js +++ b/templates/Froxlor/assets/js/jquery/updatecheck.js @@ -7,10 +7,6 @@ export default function () { runCheck(); } - $('#forceUpdateCheck').on('click', function () { - runCheck(1); - }); - function runCheck(force = 0) { $.ajax({ @@ -18,7 +14,14 @@ export default function () { type: "GET", success: function (data) { $("#updatecheck").html(data); - new bootstrap.Popover(document.getElementById('ucheck')); + const po = new bootstrap.Popover(document.getElementById('ucheck')); + const myPopoverTrigger = document.getElementById('ucheck') + myPopoverTrigger.addEventListener('shown.bs.popover', () => { + $('#forceUpdateCheck').on('click', function () { + runCheck(1); + po.hide(); + }); + }) }, error: function (request, status, error) { console.log(request, status, error) diff --git a/templates/Froxlor/misc/version_popover.html.twig b/templates/Froxlor/misc/version_popover.html.twig index 5f1c706b51..ee1642cebc 100644 --- a/templates/Froxlor/misc/version_popover.html.twig +++ b/templates/Froxlor/misc/version_popover.html.twig @@ -27,6 +27,6 @@ {% endif %} {% endif %}
- +
{% endmacro %} From c89d320957575d284f9d5b5e560432e2ce79ac2a Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 16 May 2024 08:30:35 +0200 Subject: [PATCH 32/33] use Request-wrapper-class for every access to superglobal Signed-off-by: Michael Kaufmann --- index.php | 19 +++++++------------ lib/Froxlor/UI/Pagination.php | 33 +++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/index.php b/index.php index d36b5ac672..c2f6d9116c 100644 --- a/index.php +++ b/index.php @@ -449,25 +449,20 @@ } // Pass the last used page if needed - $lastscript = ""; - if (isset($_REQUEST['script']) && $_REQUEST['script'] != "") { - $lastscript = $_REQUEST['script']; + $lastscript = Request::any('script', ''); + if (!empty($lastscript)) { $lastscript = str_replace("..", "", $lastscript); $lastscript = htmlspecialchars($lastscript, ENT_QUOTES); - if (!file_exists(__DIR__ . "/" . $lastscript)) { + if (file_exists(__DIR__ . "/" . $lastscript)) { + $_SESSION['lastscript'] = $lastscript; + } else { $lastscript = ""; } } - $lastqrystr = ""; - if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") { - $lastqrystr = urlencode($_REQUEST['qrystr']); - } - - if (!empty($lastscript)) { - $_SESSION['lastscript'] = $lastscript; - } + $lastqrystr = Request::any('qrystr', ''); if (!empty($lastqrystr)) { + $lastqrystr = urlencode($lastqrystr); $_SESSION['lastqrystr'] = $lastqrystr; } diff --git a/lib/Froxlor/UI/Pagination.php b/lib/Froxlor/UI/Pagination.php index e2f090ca0d..c746527c9f 100644 --- a/lib/Froxlor/UI/Pagination.php +++ b/lib/Froxlor/UI/Pagination.php @@ -61,11 +61,12 @@ class Pagination */ public function __construct( array $fields = [], - int $total_entries = 0, - int $perPage = 20, + int $total_entries = 0, + int $perPage = 20, array $default_sorting = [], array $pagination_additional_params = [] - ) { + ) + { $this->fields = $fields; $this->entries = $total_entries; $this->perPage = $perPage; @@ -80,12 +81,13 @@ public function __construct( $orderfields = array_keys($fields); $this->searchfield = $orderfields[0]; } - if (isset($_REQUEST['searchtext']) && (preg_match('/[-_@\p{L}\p{N}*.]+$/u', - $_REQUEST['searchtext']) || $_REQUEST['searchtext'] === '')) { - $this->searchtext = trim($_REQUEST['searchtext']); + $searchtext = Request::any('searchtext'); + if (isset($searchtext) && (preg_match('/[-_@\p{L}\p{N}*.]+$/u', $searchtext) || $searchtext === '')) { + $this->searchtext = trim($searchtext); } - if (isset($_REQUEST['searchfield']) && isset($fields[$_REQUEST['searchfield']])) { - $this->searchfield = $_REQUEST['searchfield']; + $searchfield = Request::any('searchfield'); + if (isset($searchfield) && isset($fields[$searchfield])) { + $this->searchfield = $searchfield; } if (!empty($this->searchtext) && !empty($this->searchfield)) { $this->addSearch($this->searchtext, $this->searchfield); @@ -94,11 +96,13 @@ public function __construct( } // check other ordering requests - if (isset($_REQUEST['sortorder']) && (strtolower($_REQUEST['sortorder']) == 'desc' || strtolower($_REQUEST['sortorder']) == 'asc')) { - $this->sortorder = strtoupper($_REQUEST['sortorder']); + $sortorder = Request::any('sortorder'); + if (!empty($sortorder) && (strtolower($sortorder) == 'desc' || strtolower($sortorder) == 'asc')) { + $this->sortorder = strtoupper($sortorder); } - if (isset($_REQUEST['sortfield']) && isset($fields[$_REQUEST['sortfield']])) { - $this->sortfield = $_REQUEST['sortfield']; + $sortfield = Request::any('sortfield'); + if (!empty($sortfield) && isset($fields[$sortfield])) { + $this->sortfield = $sortfield; $this->addOrderBy($this->sortfield, $this->sortorder); } else { // add default ordering by given order @@ -118,8 +122,9 @@ public function __construct( } // check current page / pages - if (isset($_REQUEST['pageno']) && intval($_REQUEST['pageno']) != 0) { - $this->pageno = intval($_REQUEST['pageno']); + $pageno = Request::any('pageno'); + if (!empty($pageno) && intval($pageno) != 0) { + $this->pageno = intval($pageno); } if (($this->pageno - 1) * Settings::Get('panel.paging') > $this->entries) { $this->pageno = 1; From 1f5982e8a0e01bac4609a7f40b0d9d8716d4405c Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Thu, 16 May 2024 08:32:55 +0200 Subject: [PATCH 33/33] update dependencies Signed-off-by: Michael Kaufmann --- composer.lock | 521 +++++++++++++++++++++++++++----------------------- 1 file changed, 284 insertions(+), 237 deletions(-) diff --git a/composer.lock b/composer.lock index 4a2234f292..929caf7142 100644 --- a/composer.lock +++ b/composer.lock @@ -201,16 +201,16 @@ }, { "name": "league/commonmark", - "version": "2.4.1", + "version": "2.4.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5" + "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3669d6d5f7a47a93c08ddff335e6d945481a1dd5", - "reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/91c24291965bd6d7c46c46a12ba7492f83b1cadf", + "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf", "shasum": "" }, "require": { @@ -223,7 +223,7 @@ }, "require-dev": { "cebe/markdown": "^1.0", - "commonmark/cmark": "0.30.0", + "commonmark/cmark": "0.30.3", "commonmark/commonmark.js": "0.30.0", "composer/package-versions-deprecated": "^1.8", "embed/embed": "^4.4", @@ -233,10 +233,10 @@ "michelf/php-markdown": "^1.4 || ^2.0", "nyholm/psr7": "^1.5", "phpstan/phpstan": "^1.8.2", - "phpunit/phpunit": "^9.5.21", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", + "symfony/finder": "^5.3 | ^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" }, @@ -303,7 +303,7 @@ "type": "tidelift" } ], - "time": "2023-08-30T16:55:00+00:00" + "time": "2024-02-02T11:59:32+00:00" }, { "name": "league/config", @@ -973,16 +973,16 @@ }, { "name": "symfony/console", - "version": "v5.4.32", + "version": "v5.4.39", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c70df1ffaf23a8d340bded3cfab1b86752ad6ed7" + "reference": "f3e591c48688a0cfa1a3296205926c05e84b22b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c70df1ffaf23a8d340bded3cfab1b86752ad6ed7", - "reference": "c70df1ffaf23a8d340bded3cfab1b86752ad6ed7", + "url": "https://api.github.com/repos/symfony/console/zipball/f3e591c48688a0cfa1a3296205926c05e84b22b1", + "reference": "f3e591c48688a0cfa1a3296205926c05e84b22b1", "shasum": "" }, "require": { @@ -1052,7 +1052,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.32" + "source": "https://github.com/symfony/console/tree/v5.4.39" }, "funding": [ { @@ -1068,20 +1068,20 @@ "type": "tidelift" } ], - "time": "2023-11-18T18:23:04+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v2.5.3", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "80d075412b557d41002320b96a096ca65aa2c98d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d", "shasum": "" }, "require": { @@ -1119,7 +1119,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.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" }, "funding": [ { @@ -1135,20 +1135,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2023-01-24T14:02:46+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -1162,9 +1162,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1201,7 +1198,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -1217,20 +1214,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1" + "reference": "cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6de50471469b8c9afc38164452ab2b6170ee71c1", - "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f", + "reference": "cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f", "shasum": "" }, "require": { @@ -1244,9 +1241,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1284,7 +1278,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.29.0" }, "funding": [ { @@ -1300,20 +1294,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", "shasum": "" }, "require": { @@ -1324,9 +1318,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1365,7 +1356,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" }, "funding": [ { @@ -1381,20 +1372,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", "shasum": "" }, "require": { @@ -1405,9 +1396,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1449,7 +1437,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" }, "funding": [ { @@ -1465,20 +1453,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { @@ -1492,9 +1480,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1532,7 +1517,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -1548,20 +1533,20 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", "shasum": "" }, "require": { @@ -1569,9 +1554,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1608,7 +1590,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" }, "funding": [ { @@ -1624,20 +1606,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", "shasum": "" }, "require": { @@ -1645,9 +1627,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1687,7 +1666,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" }, "funding": [ { @@ -1703,20 +1682,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -1724,9 +1703,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1770,7 +1746,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -1786,20 +1762,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v2.5.3", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3", + "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3", "shasum": "" }, "require": { @@ -1853,7 +1829,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.3" }, "funding": [ { @@ -1869,20 +1845,20 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2023-04-21T15:04:16+00:00" }, { "name": "symfony/string", - "version": "v5.4.32", + "version": "v5.4.39", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "91bf4453d65d8231688a04376c3a40efe0770f04" + "reference": "495e71bae5862308051b9e63cc3e34078eed83ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/91bf4453d65d8231688a04376c3a40efe0770f04", - "reference": "91bf4453d65d8231688a04376c3a40efe0770f04", + "url": "https://api.github.com/repos/symfony/string/zipball/495e71bae5862308051b9e63cc3e34078eed83ef", + "reference": "495e71bae5862308051b9e63cc3e34078eed83ef", "shasum": "" }, "require": { @@ -1939,7 +1915,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.32" + "source": "https://github.com/symfony/string/tree/v5.4.39" }, "funding": [ { @@ -1955,34 +1931,41 @@ "type": "tidelift" } ], - "time": "2023-11-26T13:43:46+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.10.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7aaed0b8311a557cc8c4047a71fd03153a00e755", + "reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -2015,7 +1998,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.10.2" }, "funding": [ { @@ -2027,7 +2010,7 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-05-14T06:04:16+00:00" }, { "name": "voku/anti-xss", @@ -2293,16 +2276,16 @@ "packages-dev": [ { "name": "composer/pcre", - "version": "3.1.1", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" + "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "url": "https://api.github.com/repos/composer/pcre/zipball/5b16e25a5355f1f3afdfc2f954a0a80aec4826a8", + "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8", "shasum": "" }, "require": { @@ -2344,7 +2327,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.1" + "source": "https://github.com/composer/pcre/tree/3.1.3" }, "funding": [ { @@ -2360,20 +2343,20 @@ "type": "tidelift" } ], - "time": "2023-10-11T07:11:09+00:00" + "time": "2024-03-19T10:26:25+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -2384,7 +2367,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -2408,9 +2391,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -2426,7 +2409,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "doctrine/instantiator", @@ -2559,25 +2542,27 @@ }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -2585,7 +2570,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2609,9 +2594,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "pdepend/pdepend", @@ -2678,20 +2663,21 @@ }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -2732,9 +2718,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -2995,16 +2987,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.50", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + "reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e524358f930e41a2b4cca1320e3b04fc26b39e0b", + "reference": "e524358f930e41a2b4cca1320e3b04fc26b39e0b", "shasum": "" }, "require": { @@ -3047,26 +3039,22 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2024-05-15T08:00:59+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", "shasum": "" }, "require": { @@ -3123,7 +3111,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.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" }, "funding": [ { @@ -3131,7 +3119,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-03-02T06:37:42+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3376,16 +3364,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.15", + "version": "9.6.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", "shasum": "" }, "require": { @@ -3459,7 +3447,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.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" }, "funding": [ { @@ -3475,20 +3463,20 @@ "type": "tidelift" } ], - "time": "2023-12-01T16:55:19+00:00" + "time": "2024-04-05T04:35:58+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -3523,7 +3511,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -3531,7 +3519,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -3777,16 +3765,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -3831,7 +3819,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -3839,7 +3827,7 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -3906,16 +3894,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -3971,7 +3959,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -3979,20 +3967,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -4035,7 +4023,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -4043,7 +4031,7 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -4341,16 +4329,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -4362,7 +4350,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -4383,8 +4371,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -4392,7 +4379,7 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -4505,16 +4492,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.0", + "version": "3.9.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/aac1f6f347a5c5ac6bc98ad395007df00990f480", + "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480", "shasum": "" }, "require": { @@ -4524,11 +4511,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -4581,20 +4568,20 @@ "type": "open_collective" } ], - "time": "2023-12-08T12:32:31+00:00" + "time": "2024-04-23T20:25:34+00:00" }, { "name": "symfony/config", - "version": "v5.4.31", + "version": "v5.4.39", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" + "reference": "62cec4a067931552624a9962002c210c502d42fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "url": "https://api.github.com/repos/symfony/config/zipball/62cec4a067931552624a9962002c210c502d42fd", + "reference": "62cec4a067931552624a9962002c210c502d42fd", "shasum": "" }, "require": { @@ -4644,7 +4631,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.31" + "source": "https://github.com/symfony/config/tree/v5.4.39" }, "funding": [ { @@ -4660,20 +4647,20 @@ "type": "tidelift" } ], - "time": "2023-11-09T08:22:43+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.33", + "version": "v5.4.39", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "14969a558cd6382b2a12b14b20ef9a851a02da79" + "reference": "5b4505f2afbe1d11d43a3917d0c1c178a38f6f19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/14969a558cd6382b2a12b14b20ef9a851a02da79", - "reference": "14969a558cd6382b2a12b14b20ef9a851a02da79", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5b4505f2afbe1d11d43a3917d0c1c178a38f6f19", + "reference": "5b4505f2afbe1d11d43a3917d0c1c178a38f6f19", "shasum": "" }, "require": { @@ -4733,7 +4720,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.33" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.39" }, "funding": [ { @@ -4749,27 +4736,28 @@ "type": "tidelift" } ], - "time": "2023-11-30T08:15:37+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.25", + "version": "v5.4.39", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" + "reference": "e6edd875d5d39b03de51f3c3951148cfa79a4d12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e6edd875d5d39b03de51f3c3951148cfa79a4d12", + "reference": "e6edd875d5d39b03de51f3c3951148cfa79a4d12", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-php80": "^1.16", + "symfony/process": "^5.4|^6.4" }, "type": "library", "autoload": { @@ -4797,7 +4785,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" + "source": "https://github.com/symfony/filesystem/tree/v5.4.39" }, "funding": [ { @@ -4813,20 +4801,20 @@ "type": "tidelift" } ], - "time": "2023-05-31T13:04:02+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", + "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", "shasum": "" }, "require": { @@ -4834,9 +4822,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4876,7 +4861,69 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.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-01-29T20:11:03+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.39", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/85a554acd7c28522241faf2e97b9541247a0d3d5", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.39" }, "funding": [ { @@ -4892,20 +4939,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-04-18T08:26:06+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -4934,7 +4981,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -4942,7 +4989,7 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], @@ -4972,5 +5019,5 @@ "platform-dev": { "ext-pcntl": "*" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" }