From a43d53d54034805e3e404702a01312fa0c40b623 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 12 Jan 2025 10:27:02 +0100 Subject: [PATCH] force admin email addresses to be unique and not be used for customers, fixes GHSA-7j6w-p859-464f Signed-off-by: Michael Kaufmann --- composer.lock | 148 ++++++++++++------------- lib/Froxlor/Api/Commands/Admins.php | 23 ++++ lib/Froxlor/Api/Commands/Customers.php | 23 ++++ lng/de.lng.php | 2 + lng/en.lng.php | 2 + 5 files changed, 124 insertions(+), 74 deletions(-) diff --git a/composer.lock b/composer.lock index b542b23d..3378416d 100644 --- a/composer.lock +++ b/composer.lock @@ -201,16 +201,16 @@ }, { "name": "league/commonmark", - "version": "2.6.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "d150f911e0079e90ae3c106734c93137c184f932" + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932", - "reference": "d150f911e0079e90ae3c106734c93137c184f932", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", "shasum": "" }, "require": { @@ -304,7 +304,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T15:34:16+00:00" + "time": "2024-12-29T14:10:59+00:00" }, { "name": "league/config", @@ -675,16 +675,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.2", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a7b17b42fa4887c92146243f3d2f4ccb962af17c", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -744,7 +744,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -752,7 +752,7 @@ "type": "github" } ], - "time": "2024-10-09T10:07:50+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "psr/container", @@ -1090,12 +1090,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1164,8 +1164,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1243,8 +1243,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1320,8 +1320,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1398,8 +1398,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1482,8 +1482,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1556,8 +1556,8 @@ "type": "metapackage", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "notification-url": "https://packagist.org/downloads/", @@ -1621,8 +1621,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1777,8 +1777,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1835,16 +1835,16 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3" + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", "shasum": "" }, "require": { @@ -1860,12 +1860,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1898,7 +1898,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" }, "funding": [ { @@ -1914,7 +1914,7 @@ "type": "tidelift" } ], - "time": "2023-04-21T15:04:16+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/string", @@ -2371,13 +2371,13 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-main": "3.x-dev" } }, "autoload": { @@ -2621,16 +2621,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -2673,9 +2673,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "pdepend/pdepend", @@ -3066,16 +3066,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.11", + "version": "1.12.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733" + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", - "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", + "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", "shasum": "" }, "require": { @@ -3120,7 +3120,7 @@ "type": "github" } ], - "time": "2024-11-17T14:08:01+00:00" + "time": "2025-01-05T16:40:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3443,16 +3443,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.21", + "version": "9.6.22", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", "shasum": "" }, "require": { @@ -3463,7 +3463,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.12.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -3526,7 +3526,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22" }, "funding": [ { @@ -3542,7 +3542,7 @@ "type": "tidelift" } ], - "time": "2024-09-19T10:50:18+00:00" + "time": "2024-12-05T13:48:26+00:00" }, { "name": "sebastian/cli-parser", @@ -4571,16 +4571,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.11.1", + "version": "3.11.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87" + "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", - "reference": "19473c30efe4f7b3cd42522d0b2e6e7f243c6f87", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", + "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", "shasum": "" }, "require": { @@ -4647,7 +4647,7 @@ "type": "open_collective" } ], - "time": "2024-11-16T12:02:36+00:00" + "time": "2024-12-11T16:04:26+00:00" }, { "name": "symfony/config", @@ -4730,16 +4730,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.45", + "version": "v5.4.48", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b" + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0c199da64bb27e4216ccccb83f451e2ec66b3c4b", - "reference": "0c199da64bb27e4216ccccb83f451e2ec66b3c4b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", "shasum": "" }, "require": { @@ -4799,7 +4799,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.45" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.48" }, "funding": [ { @@ -4815,7 +4815,7 @@ "type": "tidelift" } ], - "time": "2024-10-22T18:49:16+00:00" + "time": "2024-11-20T10:51:57+00:00" }, { "name": "symfony/filesystem", @@ -4937,7 +4937,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index 26ebb0cd..228f4497 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -287,6 +287,15 @@ class Admins extends ApiCommand implements ResourceEntity 'login' => $loginname ], true, true); + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) { Response::standardError('loginnameexists', $loginname, true); } elseif (preg_match('/^' . preg_quote(Settings::Get('customer.accountprefix'), '/') . '([0-9]+)/', $loginname)) { @@ -298,6 +307,8 @@ class Admins extends ApiCommand implements ResourceEntity Response::standardError('loginnameiswrong', $loginname, true); } elseif (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexists', $email, true); } else { if ($customers_see_all != '1') { $customers_see_all = '0'; @@ -610,8 +621,20 @@ class Admins extends ApiCommand implements ResourceEntity 'admin.email' ], '', true); } + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email and `adminid` <> :adminid + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email, + 'adminid' => $id, + ], true, true); + if (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexists', $email, true); } else { if ($deactivated != '1') { $deactivated = '0'; diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 0f193c23..4e4955ad 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -505,6 +505,15 @@ class Customers extends ApiCommand implements ResourceEntity 'login' => $loginname ], true, true); + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + $mysql_maxlen = Database::getSqlUsernameLength() - strlen(Settings::Get('customer.mysqlprefix')); if (($loginname_check && strtolower($loginname_check['loginname']) == strtolower($loginname)) || ($loginname_check_admin && strtolower($loginname_check_admin['loginname']) == strtolower($loginname))) { Response::standardError('loginnameexists', $loginname, true); @@ -514,6 +523,8 @@ class Customers extends ApiCommand implements ResourceEntity } else { Response::standardError('loginnameiswrong', $loginname, true); } + } elseif ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexistsanon', $email, true); } $guid = intval(Settings::Get('system.lastguid')) + 1; @@ -1243,6 +1254,18 @@ class Customers extends ApiCommand implements ResourceEntity ], '', true); } elseif (!Validate::validateEmail($email)) { Response::standardError('emailiswrong', $email, true); + } else { + // Check for existing email address + // do not check via api as we skip any permission checks for this task + $email_check_admin_stmt = Database::prepare(" + SELECT `email` FROM `" . TABLE_PANEL_ADMINS . "` WHERE `email` = :email + "); + $email_check_admin = Database::pexecute_first($email_check_admin_stmt, [ + 'email' => $email + ], true, true); + if ($email_check_admin && strtolower($email_check_admin['email']) == strtolower($email)) { + Response::standardError('emailexistsanon', $email, true); + } } } diff --git a/lng/de.lng.php b/lng/de.lng.php index a876e3d3..f1f75488 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -787,6 +787,8 @@ return [ 'mydocumentroot' => '\'Documentroot\'', 'loginnameexists' => 'Der Login-Name "%s" existiert bereits.', 'emailiswrong' => 'Die E-Mail-Adresse "%s" enthält ungültige Zeichen oder ist nicht vollständig.', + 'emailexists' => 'Die E-Mail-Adresse "%s" wird bereits von einem anderen Admin verwendet', + 'emailexistsanon' => 'Die E-Mail-Adresse "%s" wird bereits verwendet', 'alternativeemailiswrong' => 'Die angegebene alternative E-Mail Adresse "%s", an welche die Zugangsdaten geschickt werden soll, scheint ungültig zu sein.', 'loginnameiswrong' => 'Der Login-Name "%s" enthält ungültige Zeichen.', 'loginnameiswrong2' => 'Der Login-Name enthält zu viele Zeichen, es sind maximal %s Zeichen erlaubt.', diff --git a/lng/en.lng.php b/lng/en.lng.php index 2de83ad3..031314c0 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -858,6 +858,8 @@ return [ 'mydocumentroot' => '\'Documentroot\'', 'loginnameexists' => 'Loginname %s already exists', 'emailiswrong' => 'Email-address %s contains invalid characters or is incomplete', + 'emailexists' => 'Email-address %s already in use by another admin', + 'emailexistsanon' => 'Email-address %s already in use.', 'alternativeemailiswrong' => 'The given alternative email address %s to send the credentials to seems to be invalid', 'loginnameiswrong' => 'Loginname "%s" contains illegal characters.', 'loginnameiswrong2' => 'Loginname contains too many characters. Only %s characters are allowed.',