diff --git a/ajax/frontend/registrars/emailBlacklisted.php b/ajax/frontend/registrars/emailBlacklisted.php new file mode 100644 index 0000000000000000000000000000000000000000..1f046eaebfc1636789234a67419f413edf040dab --- /dev/null +++ b/ajax/frontend/registrars/emailBlacklisted.php @@ -0,0 +1,18 @@ +<?php + +/** + * Checks if an email address is blacklisted. + * + * @param string $email + * @return boolean + */ + +use QUI\FrontendUsers\Utils; + +QUI::$Ajax->registerFunction( + 'package_quiqqer_frontend-users_ajax_frontend_registrars_emailBlacklisted', + function ($email) { + return Utils::isEmailBlacklisted($email); + }, + ['email'] +); diff --git a/ajax/frontend/registrars/emailExists.php b/ajax/frontend/registrars/emailExists.php index dd40f1c894cf97787aaff0ac27f6ac47e2303f43..c0aa49a7c355146bfefada7ff8ecdae4afdad3b7 100644 --- a/ajax/frontend/registrars/emailExists.php +++ b/ajax/frontend/registrars/emailExists.php @@ -1,16 +1,22 @@ <?php /** - * check, if this is a username which can be used + * check, if this is a email which can be used * * @param string $username * * @return boolean */ +use QUI\Utils\Security\Orthos; + QUI::$Ajax->registerFunction( 'package_quiqqer_frontend-users_ajax_frontend_registrars_emailExists', function ($email) { + if (!Orthos::checkMailSyntax($email)) { + return false; + } + return QUI::getUsers()->emailExists($email); }, ['email'] diff --git a/bin/frontend/classes/Registration.js b/bin/frontend/classes/Registration.js index 2493f728117405bdf4d69dc75973bef49a478732..b287415e58ce4ea6bd06f85978e6ca4b57e8e0fd 100644 --- a/bin/frontend/classes/Registration.js +++ b/bin/frontend/classes/Registration.js @@ -49,6 +49,22 @@ define('package/quiqqer/frontend-users/bin/frontend/classes/Registration', [ }); }, + /** + * Check if an email address is blacklisted. + * + * @param {String} email + * @return {Promise<Boolean>} + */ + isEmailBlacklisted: function(email) { + return new Promise(function (resolve, reject) { + QUIAjax.get('package_quiqqer_frontend-users_ajax_frontend_registrars_emailBlacklisted', resolve, { + 'package': pkg, + email : email, + onError : reject + }); + }); + }, + /** * Execute username validation * diff --git a/bin/frontend/controls/RegistrationSignUp.js b/bin/frontend/controls/RegistrationSignUp.js index d3e98ffa841937a4ee565c62afea0185e4b7732d..8c3a80ec4da1dc533dd6b4ab912f54c208f34fb9 100644 --- a/bin/frontend/controls/RegistrationSignUp.js +++ b/bin/frontend/controls/RegistrationSignUp.js @@ -849,7 +849,6 @@ define('package/quiqqer/frontend-users/bin/frontend/controls/RegistrationSignUp' // self.emailValidation(EmailField); // }).delay(2000); //}); - EmailField.addEvent('keydown', function (event) { if (event.key === 'enter') { event.stop(); @@ -1039,7 +1038,16 @@ define('package/quiqqer/frontend-users/bin/frontend/controls/RegistrationSignUp' ButtonTrial.set('disabled', true); } - this.emailValidation(MailInput).then(function (isValid) { + Registration.isEmailBlacklisted(MailInput.value).then((isBlacklisted) => { + if (isBlacklisted) { + QUI.getMessageHandler((MH) => { + MH.addAttention(QUILocale.get(lg, 'exception.registrars.email.email_blacklisted'), MailInput); + }); + return false; + } + + return this.emailValidation(MailInput); + }).then(function (isValid) { if (!isValid) { return Promise.reject('isInValid'); } diff --git a/locale.xml b/locale.xml index 7fe2690fde37151846673484a34aba51921c633d..2785dd9f29dd1551109dbe9c30298fee8bc11f55 100644 --- a/locale.xml +++ b/locale.xml @@ -2,6 +2,10 @@ <locales> <groups name="quiqqer/frontend-users" datatype="php,js"> + <locale name="exception.registrars.email.email_blacklisted"> + <de><![CDATA[Die eingegebene E-Mail-Adresse kann nicht verwendet werden, da sie Wortbestandteile enthält, die nicht zugelassen sind.]]></de> + <en><![CDATA[The e-mail address entered cannot be used because it contains word components that are not permitted.]]></en> + </locale> <!-- Cron --> <locale name="cron.deleteUnverifiedInactiveUsers.title"> <de><![CDATA[Nicht aktive Benutzer löschen]]></de> @@ -926,8 +930,10 @@ <en><![CDATA[Frontend-Users: Content by auth status and group(s)]]></en> </locale> <locale name="brick.AuthContent.description"> - <de><![CDATA[Zeigt jeweils spezifischen Content, wenn ein Benutzer nicht eingeloggt, nicht in einer Gruppe oder in einer Gruppe ist.]]></de> - <en><![CDATA[Shows specific content each time a user is not logged in, not in a group, or in a group.]]></en> + <de> + <![CDATA[Zeigt jeweils spezifischen Content, wenn ein Benutzer nicht eingeloggt, nicht in einer Gruppe oder in einer Gruppe ist.]]></de> + <en> + <![CDATA[Shows specific content each time a user is not logged in, not in a group, or in a group.]]></en> </locale> <locale name="brick.AuthContent.settings.content_guest.title"> <de><![CDATA[Inhalt (Gast)]]></de> @@ -974,8 +980,10 @@ Available placeholders: <en><![CDATA[Groups]]></en> </locale> <locale name="brick.AuthContent.settings.groups.description"> - <de><![CDATA[Liste der Gruppe, von denen sich der Benutzer mindestens einer zugeordnet sein muss, um den "Inhalt (in Gruppe(n))"-Inhalt angezeigt zu bekommen.]]></de> - <en><![CDATA[List of groups from which the user must be assigned to at least one to see the "Content (in group(s))" content.]]></en> + <de> + <![CDATA[Liste der Gruppe, von denen sich der Benutzer mindestens einer zugeordnet sein muss, um den "Inhalt (in Gruppe(n))"-Inhalt angezeigt zu bekommen.]]></de> + <en> + <![CDATA[List of groups from which the user must be assigned to at least one to see the "Content (in group(s))" content.]]></en> </locale> <locale name="mail.delete_user_confirm.subject.description"> @@ -1075,6 +1083,34 @@ Available placeholders: </groups> <groups name="quiqqer/frontend-users" datatype="php"> + <locale name="settings.registration.emailBlacklist"> + <de><![CDATA[Registrierung E-Mail Blacklist]]></de> + <en><![CDATA[Registration email blacklist]]></en> + </locale> + <locale name="settings.registration.emailBlacklist.description" html="true"> + <de><![CDATA[ +<p>Liste von E-Mail-Adressen oder Teilen von E-Mail-Adressen, mit denen sich Benutzer nicht registrieren dürfen.</p> +<p><b>Ein Eintrag pro Zeile!</b></p> +<p>Beispiele: +<ul> +<li><b>user@mail.com</b> - Verbietet eine explizite E-Mail-Adresse</li> +<li><b>*@mail.com</b> - Verbietet alle E-Mail-Adressen der Domain "mail.com"</li> +<li><b>user@*</b> - Verbietet alle E-Mail-Adressen, die mit user@ beginnen (unabhängig von der Domain)</li> +</ul> +</p> +]]></de> + <en><![CDATA[ +<p>List of email addresses or parts of email addresses users are not permitted to register with.</p> +<p><b>One entry per line!</b></p> +<p>Examples: +<ul> +<li><b>user@mail.com</b> - Proibits an explicit email address</li> +<li><b>*@mail.com</b> - Prohibits all email addresses of the domain "mail.com"</li> +<li><b>user@*</b> - Prhoibits all email addresses that start with "user@" (independent of the domain)</li> +</ul> +</p> +]]></en> + </locale> <locale name="GdprDataProvider.title"> <de><![CDATA[Daten aus Benutzerregistrierung]]></de> diff --git a/settings.xml b/settings.xml index 9b2941aecadda3f28758b013d3d101309ab6ee49..353ab41a24b19a0d2b068d6d4c04bf927594894a 100644 --- a/settings.xml +++ b/settings.xml @@ -157,6 +157,9 @@ <conf name="privacyPolicySite"> <type><![CDATA[string]]></type> </conf> + <conf name="emailBlacklist"> + <type><![CDATA[string]]></type> + </conf> </section> <section name="profile"> @@ -645,6 +648,21 @@ </description> </input> + <textarea + conf="registration.emailBlacklist" + data-qui="package/quiqqer/core/bin/QUI/controls/settings/Textarea" + rows="15" + > + <text> + <locale group="quiqqer/frontend-users" + var="settings.registration.emailBlacklist"/> + </text> + <description> + <locale group="quiqqer/frontend-users" + var="settings.registration.emailBlacklist.description"/> + </description> + </textarea> + </settings> </category> diff --git a/src/QUI/FrontendUsers/Registrars/Email/Registrar.php b/src/QUI/FrontendUsers/Registrars/Email/Registrar.php index cb0f6a7c984c4a56de34dd93d234db9a387c1ead..5777aefb320930d8ac559420f0c3d73d3ed29711 100644 --- a/src/QUI/FrontendUsers/Registrars/Email/Registrar.php +++ b/src/QUI/FrontendUsers/Registrars/Email/Registrar.php @@ -195,6 +195,13 @@ public function validate(): array ]); } + if (FrontendUsers\Utils::isEmailBlacklisted($email)) { + throw new FrontendUsers\Exception([ + $lg, + $lgPrefix . 'email_blacklisted' + ]); + } + // Address validation if ($this->getAttribute('addressValidation') && (int)$settings['addressInput']) { foreach ($Handler->getAddressFieldSettings() as $field => $addressSettings) { diff --git a/src/QUI/FrontendUsers/Utils.php b/src/QUI/FrontendUsers/Utils.php index 393756dd5c136f52e658611500706d2fd3d93ae9..4a6c410b90420ca2106ee46e90119a33eadd601e 100644 --- a/src/QUI/FrontendUsers/Utils.php +++ b/src/QUI/FrontendUsers/Utils.php @@ -1,13 +1,17 @@ <?php +/** + * This file contains QUI\FrontendUsers\Utils + */ + namespace QUI\FrontendUsers; use QUI; use QUI\FrontendUsers\Controls\Profile\ControlInterface; -use QUI\Package\Package; -use QUI\Permissions; -use QUI\Interfaces\Users\User as QUIUserInterface; use QUI\FrontendUsers\Exception\EmailAddressNotVerifiableException; +use QUI\Interfaces\Users\User as QUIUserInterface; +use QUI\Permissions; +use QUI\Utils\Security\Orthos; use function class_exists; use function in_array; @@ -628,4 +632,73 @@ public static function getMissingAddressFields(QUI\Users\Address $Address): arra return $missing; } + + /** + * Check if an email address is blacklisted from registration. + * + * @param string $email + * @return bool + */ + public static function isEmailBlacklisted(string $email): bool + { + foreach (self::getBlacklistedEmailPatterns() as $pattern) { + if (self::doesEmailMatchPattern($email, $pattern)) { + return true; + } + } + + return false; + } + + /** + * @param string $email + * @param string $pattern + * @return bool + */ + private static function doesEmailMatchPattern(string $email, string $pattern): bool + { + if (!Orthos::checkMailSyntax($email)) { + return false; + } + + $partsPattern = explode('@', $pattern); + + if (empty($partsPattern[1])) { + return false; + } + + $patternName = $partsPattern[0]; + $patternNameIsWildcard = $patternName === '*'; + $patternDomain = $partsPattern[1]; + $patternDomainIsWildcard = $patternDomain === '*'; + + $partsEmail = explode('@', $email); + $emailName = $partsEmail[0]; + $emailDomain = $partsEmail[1]; + + $nameMatch = $patternNameIsWildcard || $emailName === $patternName; + $domainMatch = $patternDomainIsWildcard || $emailDomain === $patternDomain; + + return $nameMatch && $domainMatch; + } + + /** + * @return array + */ + private static function getBlacklistedEmailPatterns(): array + { + try { + $Conf = QUI::getPackage('quiqqer/frontend-users')->getConfig(); + $setting = $Conf->get('registration', 'emailBlacklist'); + } catch (\Exception $Exception) { + QUI\System\Log::writeException($Exception); + return []; + } + + if (empty($setting)) { + return []; + } + + return json_decode($setting, true); + } }