From 81fb98548d2f86b131e8f4989973023060bf36c6 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Wed, 23 Apr 2025 16:19:33 +0200 Subject: [PATCH 01/26] start logic --- lib/Service/RecoveryEmailService.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index e4532ff..2a300a1 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -180,6 +180,11 @@ class RecoveryEmailService { $this->logger->info("User ID $username's requested recovery email address is already taken"); throw new RecoveryEmailAlreadyFoundException($l->t('Recovery email address is already taken.')); } + + if ($this->isRecoveryExtendedEmailAbused($username, $recoveryEmail)) { + $this->logger->info("User ID $username's requested recovery email address is already taken"); + throw new RecoveryEmailAlreadyFoundException($l->t('Recovery email address is already taken.')); + } if ($this->isRecoveryEmailDomainDisallowed($recoveryEmail)) { $this->logger->info("User ID $username's requested recovery email address is disallowed."); @@ -341,6 +346,29 @@ class RecoveryEmailService { return false; } + public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { + $recoveryEmail = strtolower($recoveryEmail); + + $currentRecoveryEmail = $this->getRecoveryEmail($username); + $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); + + if ($currentRecoveryEmail === $recoveryEmail || $currentUnverifiedRecoveryEmail === $recoveryEmail) { + return false; + } + + $usersWithEmailRecovery = $this->config->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmail); + if (count($usersWithEmailRecovery)>5) { + return true; + } + + $usersWithUnverifiedRecovery = $this->config->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmail); + if (count($usersWithUnverifiedRecovery)>5) { + return true; + } + + return false; + } + public function updateRecoveryEmail(string $username, string $recoveryEmail) : void { $this->setUnverifiedRecoveryEmail($username, $recoveryEmail); $this->setRecoveryEmail($username, ''); -- GitLab From 145a4e9bfaeb4dd6ac33f73101cc694dbf455988 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Thu, 24 Apr 2025 11:55:19 +0200 Subject: [PATCH 02/26] regex for mail + global count --- lib/Service/RecoveryEmailService.php | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 2a300a1..5ba7c8d 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -348,21 +348,13 @@ class RecoveryEmailService { public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { $recoveryEmail = strtolower($recoveryEmail); - - $currentRecoveryEmail = $this->getRecoveryEmail($username); - $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); - - if ($currentRecoveryEmail === $recoveryEmail || $currentUnverifiedRecoveryEmail === $recoveryEmail) { - return false; - } - - $usersWithEmailRecovery = $this->config->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmail); - if (count($usersWithEmailRecovery)>5) { - return true; - } - - $usersWithUnverifiedRecovery = $this->config->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmail); - if (count($usersWithUnverifiedRecovery)>5) { + $mailParts = strtok($recoveryEmail, '@'); + $recoveryEmailPrefix = $mailParts[0]; + $recoveryEmailPostfix = $mailParts[1]; + $recoveryMailregex = $recoveryEmailPrefix."+%@".$recoveryEmailPostfix; + $usersWithEmailRecovery = $this->config->getUsersForUserValue($this->appName, 'recovery-email', $recoveryMailregex); + $usersWithUnverifiedRecovery = $this->config->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryMailregex); + if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 5) { return true; } -- GitLab From 54452264ebc17b777f4a5a39cb7f22e8a24f80bb Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Thu, 24 Apr 2025 12:40:46 +0200 Subject: [PATCH 03/26] use our own mapper --- lib/Db/RecoveryMapper.php | 30 ++++++++++++++++++++++++++++ lib/Service/RecoveryEmailService.php | 19 ++++++++++++++---- 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 lib/Db/RecoveryMapper.php diff --git a/lib/Db/RecoveryMapper.php b/lib/Db/RecoveryMapper.php new file mode 100644 index 0000000..3e2cf99 --- /dev/null +++ b/lib/Db/RecoveryMapper.php @@ -0,0 +1,30 @@ +connection = $connection; + } + + + public function getUsersForUserValue($appName, $key, $value) { + $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' . + 'WHERE `appid` = ? AND `configkey` = ? AND `configvalue` like ?'; + $result = $this->connection->executeQuery($sql, [$appName, $key, $value]); + + $userIDs = []; + while ($row = $result->fetch()) { + $userIDs[] = $row['userid']; + } + + return $userIDs; + } +} diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 5ba7c8d..3cd9e01 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -11,6 +11,8 @@ use OCA\EmailRecovery\Exception\MurenaDomainDisallowedException; use OCA\EmailRecovery\Exception\RecoveryEmailAlreadyFoundException; use OCA\EmailRecovery\Exception\SameRecoveryEmailAsEmailException; use OCA\EmailRecovery\Exception\TooManyVerificationAttemptsException; +use OCA\EmailRecovery\Db\RecoveryMapper; + use OCP\Defaults; use OCP\IConfig; use OCP\IL10N; @@ -40,6 +42,7 @@ class RecoveryEmailService { private ICacheFactory $cacheFactory; private CurlService $curl; private IClientService $httpClientService; + private RecoveryMapper $recoveryMapper; private array $apiConfig; protected const TOKEN_LIFETIME = 60 * 30; // 30 minutes private const ATTEMPT_KEY = "recovery_email_attempts"; @@ -53,7 +56,7 @@ class RecoveryEmailService { private IL10N $l; private ISession $session; - public function __construct(string $appName, ILogger $logger, IConfig $config, ISession $session, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken, CurlService $curlService, DomainService $domainService, IL10N $l, ICacheFactory $cacheFactory, IClientService $httpClientService) { + public function __construct(string $appName, ILogger $logger, IConfig $config, ISession $session, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken, CurlService $curlService, DomainService $domainService, IL10N $l, ICacheFactory $cacheFactory, IClientService $httpClientService, RecoveryMapper $recoveryMapper) { $this->logger = $logger; $this->config = $config; $this->appName = $appName; @@ -70,6 +73,7 @@ class RecoveryEmailService { $this->l = $l; $this->cacheFactory = $cacheFactory; // Initialize the cache factory $this->cache = $this->cacheFactory->createDistributed(self::CACHE_KEY); // Initialize the cache + $this->recoveryMapper = $recoveryMapper; $commonServiceURL = $this->config->getSystemValue('common_services_url', ''); if (!empty($commonServiceURL)) { @@ -352,9 +356,16 @@ class RecoveryEmailService { $recoveryEmailPrefix = $mailParts[0]; $recoveryEmailPostfix = $mailParts[1]; $recoveryMailregex = $recoveryEmailPrefix."+%@".$recoveryEmailPostfix; - $usersWithEmailRecovery = $this->config->getUsersForUserValue($this->appName, 'recovery-email', $recoveryMailregex); - $usersWithUnverifiedRecovery = $this->config->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryMailregex); - if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 5) { + $currentRecoveryEmail = $this->getRecoveryEmail($username); + $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); + + if ($currentRecoveryEmail === $recoveryEmail || $currentUnverifiedRecoveryEmail === $recoveryEmail) { + return false; + } + + $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryMailregex); + $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryMailregex); + if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 0) { return true; } -- GitLab From b630df41e9ae46baf329d6ad5952ea4591e827ca Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Thu, 24 Apr 2025 14:57:34 +0200 Subject: [PATCH 04/26] return false if first already set mail is prefix+whatever@domain --- lib/Service/RecoveryEmailService.php | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 3cd9e01..69c7c11 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -350,16 +350,31 @@ class RecoveryEmailService { return false; } + private function getPrefixAndDomainMail(string $mail){ + if (!str_contains($mail, '+')){ + return false; + } + $mail = strtolower($mail); + $mailParts = explode('@', $mail); + $mailPartsPlus = explode('+', $mailParts[0]); + $mailPrefix = $mailPartsPlus[0]; + $mailPostfix = $mailParts[1]; + return [$mailPrefix, $mailPostfix]; + } + public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { - $recoveryEmail = strtolower($recoveryEmail); - $mailParts = strtok($recoveryEmail, '@'); - $recoveryEmailPrefix = $mailParts[0]; - $recoveryEmailPostfix = $mailParts[1]; - $recoveryMailregex = $recoveryEmailPrefix."+%@".$recoveryEmailPostfix; + $recoveryMailParts = $this->getPrefixAndDomainMail($recoveryEmail); + if (!$recoveryMailParts){ + return false; + } + $recoveryMailregex = $recoveryMailParts[0]."+%@".$recoveryMailParts[1]; $currentRecoveryEmail = $this->getRecoveryEmail($username); $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); + $currentRecoveryEmailParts = $this->getPrefixAndDomainMail($currentRecoveryEmail); + $currentUnverifiedRecoveryEmailParts = $this->getPrefixAndDomainMail($currentUnverifiedRecoveryEmail); - if ($currentRecoveryEmail === $recoveryEmail || $currentUnverifiedRecoveryEmail === $recoveryEmail) { + if ($currentRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentRecoveryEmailParts[1] === $recoveryMailParts[1] + || $currentUnverifiedRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryMailParts[1]) { return false; } -- GitLab From 1e8067b724b7fd382da030457a7d03c85e12647d Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Thu, 24 Apr 2025 15:00:34 +0200 Subject: [PATCH 05/26] lint --- lib/Db/RecoveryMapper.php | 4 +--- lib/Service/RecoveryEmailService.php | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/Db/RecoveryMapper.php b/lib/Db/RecoveryMapper.php index 3e2cf99..661fcc7 100644 --- a/lib/Db/RecoveryMapper.php +++ b/lib/Db/RecoveryMapper.php @@ -5,8 +5,6 @@ namespace OCA\EmailRecovery\Db; use OCP\IDBConnection; class RecoveryMapper { - - /** @var IDBConnection */ private $connection; @@ -15,7 +13,7 @@ class RecoveryMapper { } - public function getUsersForUserValue($appName, $key, $value) { + public function getUsersForUserValue($appName, $key, $value) { $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' . 'WHERE `appid` = ? AND `configkey` = ? AND `configvalue` like ?'; $result = $this->connection->executeQuery($sql, [$appName, $key, $value]); diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 69c7c11..6512986 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -350,8 +350,8 @@ class RecoveryEmailService { return false; } - private function getPrefixAndDomainMail(string $mail){ - if (!str_contains($mail, '+')){ + private function getPrefixAndDomainMail(string $mail) { + if (!str_contains($mail, '+')) { return false; } $mail = strtolower($mail); @@ -364,7 +364,7 @@ class RecoveryEmailService { public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { $recoveryMailParts = $this->getPrefixAndDomainMail($recoveryEmail); - if (!$recoveryMailParts){ + if (!$recoveryMailParts) { return false; } $recoveryMailregex = $recoveryMailParts[0]."+%@".$recoveryMailParts[1]; @@ -373,7 +373,7 @@ class RecoveryEmailService { $currentRecoveryEmailParts = $this->getPrefixAndDomainMail($currentRecoveryEmail); $currentUnverifiedRecoveryEmailParts = $this->getPrefixAndDomainMail($currentUnverifiedRecoveryEmail); - if ($currentRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentRecoveryEmailParts[1] === $recoveryMailParts[1] + if ($currentRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentRecoveryEmailParts[1] === $recoveryMailParts[1] || $currentUnverifiedRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryMailParts[1]) { return false; } -- GitLab From 82a57f23fe69eff585ee9e1d89c1de4bd7027019 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Thu, 24 Apr 2025 15:45:17 +0200 Subject: [PATCH 06/26] translation --- l10n/de_DE.js | 3 ++- l10n/de_DE.json | 3 ++- l10n/es.js | 3 ++- l10n/es.json | 3 ++- l10n/fr.js | 3 ++- l10n/fr.json | 3 ++- l10n/it.js | 3 ++- l10n/it.json | 3 ++- lib/Service/RecoveryEmailService.php | 4 ++-- 9 files changed, 18 insertions(+), 10 deletions(-) diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 958651a..c0f8c7b 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -38,6 +38,7 @@ OC.L10N.register( "The email could not be verified. Please try again later.": "Die E-Mail konnte nicht verifiziert werden. Bitte versuchen Sie es später noch einmal.", "The email address is disposable. Please provide another recovery address." : "Die E-Mail-Adresse ist eine Wegwerfadresse. Bitte geben Sie eine andere Wiederherstellungsadresse an.", "The email address is not deliverable. Please provide another recovery address.": "Die E-Mail Adresse ist nicht zustellbar. Bitte geben Sie eine andere Wiederherstellungsadresse an.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace wird bald wieder vollständig verfügbar sein! Bitte lesen Sie diesen Leitfaden, um mehr zu erfahren." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace wird bald wieder vollständig verfügbar sein! Bitte lesen Sie diesen Leitfaden, um mehr zu erfahren.", + "This email address in invalid, please use another one.":"Diese E-Mail-Adresse ist ungültig, bitte verwenden Sie eine andere." }, "nplurals=2; plural=n != 1;"); diff --git a/l10n/de_DE.json b/l10n/de_DE.json index 79b0c2f..ee6e86a 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -36,6 +36,7 @@ "The email could not be verified. Please try again later.": "Die E-Mail konnte nicht verifiziert werden. Bitte versuchen Sie es später noch einmal.", "The email address is disposable. Please provide another recovery address." : "Die E-Mail-Adresse ist eine Wegwerfadresse. Bitte geben Sie eine andere Wiederherstellungsadresse an.", "The email address is not deliverable. Please provide another recovery address.": "Die E-Mail Adresse ist nicht zustellbar. Bitte geben Sie eine andere Wiederherstellungsadresse an.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace wird bald wieder vollständig verfügbar sein! Bitte lesen Sie diesen Leitfaden, um mehr zu erfahren." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace wird bald wieder vollständig verfügbar sein! Bitte lesen Sie diesen Leitfaden, um mehr zu erfahren.", + "This email address in invalid, please use another one.":"Diese E-Mail-Adresse ist ungültig, bitte verwenden Sie eine andere." },"pluralForm" :"nplurals=2; plural=n != 1;" } \ No newline at end of file diff --git a/l10n/es.js b/l10n/es.js index 618b8a4..5478cf6 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -38,6 +38,7 @@ OC.L10N.register( "The email could not be verified. Please try again later.": "No se ha podido verificar el correo electrónico. Inténtelo de nuevo más tarde.", "The email address is disposable. Please provide another recovery address." : "La dirección de correo electrónico es desechable. Por favor, proporcione otra dirección de recuperación.", "The email address is not deliverable. Please provide another recovery address.": "La dirección de correo electrónico no se puede entregar. Por favor, proporcione otra dirección de recuperación.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "¡Murena Workspace estará de vuelta al 100% pronto! Por favor lee esta guía para saber más." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "¡Murena Workspace estará de vuelta al 100% pronto! Por favor lee esta guía para saber más.", + "This email address in invalid, please use another one.":"Esta dirección de correo electrónico no es válida, por favor utiliza otra." }, "nplurals=2; plural=n != 1;"); diff --git a/l10n/es.json b/l10n/es.json index fd06741..79d25d7 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -36,6 +36,7 @@ "The email could not be verified. Please try again later.": "No se ha podido verificar el correo electrónico. Inténtelo de nuevo más tarde.", "The email address is disposable. Please provide another recovery address." : "La dirección de correo electrónico es desechable. Por favor, proporcione otra dirección de recuperación.", "The email address is not deliverable. Please provide another recovery address.": "La dirección de correo electrónico no se puede entregar. Por favor, proporcione otra dirección de recuperación.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "¡Murena Workspace estará de vuelta al 100% pronto! Por favor lee esta guía para saber más." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "¡Murena Workspace estará de vuelta al 100% pronto! Por favor lee esta guía para saber más.", + "This email address in invalid, please use another one.":"Esta dirección de correo electrónico no es válida, por favor utiliza otra." },"pluralForm" :"nplurals=2; plural=n != 1;" } \ No newline at end of file diff --git a/l10n/fr.js b/l10n/fr.js index 9124408..1754bcf 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -38,6 +38,7 @@ OC.L10N.register( "The email could not be verified. Please try again later.": "L'e-mail n'a pas pu être vérifié. Veuillez réessayer plus tard.", "The email address is disposable. Please provide another recovery address." : "L'adresse électronique est jetable. Veuillez fournir une autre adresse de récupération.", "The email address is not deliverable. Please provide another recovery address.": "L'adresse électronique ne peut être délivrée. Veuillez fournir une autre adresse de recouvrement.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace sera bientôt complètement de retour ! Veuillez lire ce guide pour en savoir plus." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace sera bientôt complètement de retour ! Veuillez lire ce guide pour en savoir plus.", + "This email address in invalid, please use another one.":"Cette adresse e-mail est invalide, veuillez en utiliser une autre." }, "nplurals=2; plural=n > 1;"); diff --git a/l10n/fr.json b/l10n/fr.json index 15b667e..ccb6999 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -36,6 +36,7 @@ "The email could not be verified. Please try again later.": "L'e-mail n'a pas pu être vérifié. Veuillez réessayer plus tard.", "The email address is disposable. Please provide another recovery address." : "L'adresse électronique est jetable. Veuillez fournir une autre adresse de récupération.", "The email address is not deliverable. Please provide another recovery address.": "L'adresse électronique ne peut être délivrée. Veuillez fournir une autre adresse de recouvrement.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace sera bientôt complètement de retour ! Veuillez lire ce guide pour en savoir plus." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace sera bientôt complètement de retour ! Veuillez lire ce guide pour en savoir plus.", + "This email address in invalid, please use another one.":"Cette adresse e-mail est invalide, veuillez en utiliser une autre." },"pluralForm" :"nplurals=2; plural=n > 1;" } \ No newline at end of file diff --git a/l10n/it.js b/l10n/it.js index 35888db..1ed39f1 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -38,6 +38,7 @@ OC.L10N.register( "The email could not be verified. Please try again later.": "Non è stato possibile verificare l'e-mail. Si prega di riprovare più tardi.", "The email address is disposable. Please provide another recovery address." : "L'indirizzo e-mail è monouso. Si prega di fornire un altro indirizzo di recupero.", "The email address is not deliverable. Please provide another recovery address.": "The email address is not deliverable. Please provide another recovery address.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace tornerà presto completamente operativo! Si prega di leggere questa guida per saperne di più." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace tornerà presto completamente operativo! Si prega di leggere questa guida per saperne di più.", + "This email address in invalid, please use another one.":"Questo indirizzo email non è valido, per favore usane un altro." }, "nplurals=2; plural=n != 1;"); diff --git a/l10n/it.json b/l10n/it.json index 5f0c7de..21e38a0 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -36,6 +36,7 @@ "The email could not be verified. Please try again later.": "Non è stato possibile verificare l'e-mail. Si prega di riprovare più tardi.", "The email address is disposable. Please provide another recovery address." : "L'indirizzo e-mail è monouso. Si prega di fornire un altro indirizzo di recupero.", "The email address is not deliverable. Please provide another recovery address.": "The email address is not deliverable. Please provide another recovery address.", - "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace tornerà presto completamente operativo! Si prega di leggere questa guida per saperne di più." + "Murena Workspace will be back fully soon! Please read this guide to know more.": "Murena Workspace tornerà presto completamente operativo! Si prega di leggere questa guida per saperne di più.", + "This email address in invalid, please use another one.":"Questo indirizzo email non è valido, per favore usane un altro." },"pluralForm" :"nplurals=2; plural=n != 1;" } \ No newline at end of file diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 6512986..8d41191 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -186,8 +186,8 @@ class RecoveryEmailService { } if ($this->isRecoveryExtendedEmailAbused($username, $recoveryEmail)) { - $this->logger->info("User ID $username's requested recovery email address is already taken"); - throw new RecoveryEmailAlreadyFoundException($l->t('Recovery email address is already taken.')); + $this->logger->info("User ID $username's requested recovery extended email address is already taken"); + throw new RecoveryEmailAlreadyFoundException($l->t('This email address in invalid, please use another one.')); } if ($this->isRecoveryEmailDomainDisallowed($recoveryEmail)) { -- GitLab From 0a5b7ed430dfa9901369a9784400f46d8f384d3f Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 11:35:23 +0200 Subject: [PATCH 07/26] mail -> email --- lib/Service/RecoveryEmailService.php | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 8d41191..ff4ca1e 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -350,36 +350,36 @@ class RecoveryEmailService { return false; } - private function getPrefixAndDomainMail(string $mail) { - if (!str_contains($mail, '+')) { + private function getPrefixAndDomainEmail(string $email) { + if (!str_contains($email, '+')) { return false; } - $mail = strtolower($mail); - $mailParts = explode('@', $mail); - $mailPartsPlus = explode('+', $mailParts[0]); - $mailPrefix = $mailPartsPlus[0]; - $mailPostfix = $mailParts[1]; - return [$mailPrefix, $mailPostfix]; + $email = strtolower($email); + $emailParts = explode('@', $email); + $emailPartsPlus = explode('+', $emailParts[0]); + $emailPrefix = $emailPartsPlus[0]; + $emailPostfix = $emailParts[1]; + return [$emailPrefix, $emailPostfix]; } public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { - $recoveryMailParts = $this->getPrefixAndDomainMail($recoveryEmail); - if (!$recoveryMailParts) { + $recoveryEmailParts = $this->getPrefixAndDomainEmail($recoveryEmail); + if (!$recoveryEmailParts) { return false; } - $recoveryMailregex = $recoveryMailParts[0]."+%@".$recoveryMailParts[1]; + $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; $currentRecoveryEmail = $this->getRecoveryEmail($username); $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); - $currentRecoveryEmailParts = $this->getPrefixAndDomainMail($currentRecoveryEmail); - $currentUnverifiedRecoveryEmailParts = $this->getPrefixAndDomainMail($currentUnverifiedRecoveryEmail); + $currentRecoveryEmailParts = $this->getPrefixAndDomainEmail($currentRecoveryEmail); + $currentUnverifiedRecoveryEmailParts = $this->getPrefixAndDomainEmail($currentUnverifiedRecoveryEmail); - if ($currentRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentRecoveryEmailParts[1] === $recoveryMailParts[1] - || $currentUnverifiedRecoveryEmailParts[0] === $recoveryMailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryMailParts[1]) { + if ($currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] + || $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { return false; } - $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryMailregex); - $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryMailregex); + $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); + $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 0) { return true; } -- GitLab From e1b7495593cbbeeb00e5578fb9497afc240a1acc Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 11:38:39 +0200 Subject: [PATCH 08/26] limit to 5 --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index ff4ca1e..3fcccb0 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -380,7 +380,7 @@ class RecoveryEmailService { $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); - if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 0) { + if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 5) { return true; } -- GitLab From a98ace626530de55d0d36c3919ec6eed38d68f2e Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 11:41:46 +0200 Subject: [PATCH 09/26] set limit as system config --- lib/Service/RecoveryEmailService.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 3fcccb0..2c3fd2c 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -367,6 +367,10 @@ class RecoveryEmailService { if (!$recoveryEmailParts) { return false; } + $emailAliasLimit = $this->config->getSystemValue('email_alias_limit', '5'); + if($emailAliasLimit == -1) { + return false; + } $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; $currentRecoveryEmail = $this->getRecoveryEmail($username); $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); @@ -380,7 +384,7 @@ class RecoveryEmailService { $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); - if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > 5) { + if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > $emailAliasLimit) { return true; } -- GitLab From 6dc44f375202e0510db8e4413dfe0ffdb956e9cc Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 11:42:59 +0200 Subject: [PATCH 10/26] change variable name to mailDomain --- lib/Service/RecoveryEmailService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 2c3fd2c..9baf87e 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -358,8 +358,8 @@ class RecoveryEmailService { $emailParts = explode('@', $email); $emailPartsPlus = explode('+', $emailParts[0]); $emailPrefix = $emailPartsPlus[0]; - $emailPostfix = $emailParts[1]; - return [$emailPrefix, $emailPostfix]; + $mailDomain = $emailParts[1]; + return [$emailPrefix, $mailDomain]; } public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { -- GitLab From fd3feac3c4bbb4db2299cb1de8e05621eecd654d Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 11:45:25 +0200 Subject: [PATCH 11/26] change name to config mapper --- lib/Db/{RecoveryMapper.php => ConfigMapper.php} | 2 +- lib/Service/RecoveryEmailService.php | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) rename lib/Db/{RecoveryMapper.php => ConfigMapper.php} (96%) diff --git a/lib/Db/RecoveryMapper.php b/lib/Db/ConfigMapper.php similarity index 96% rename from lib/Db/RecoveryMapper.php rename to lib/Db/ConfigMapper.php index 661fcc7..86c92f9 100644 --- a/lib/Db/RecoveryMapper.php +++ b/lib/Db/ConfigMapper.php @@ -4,7 +4,7 @@ namespace OCA\EmailRecovery\Db; use OCP\IDBConnection; -class RecoveryMapper { +class ConfigMapper { /** @var IDBConnection */ private $connection; diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 9baf87e..5fab3ff 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -11,8 +11,7 @@ use OCA\EmailRecovery\Exception\MurenaDomainDisallowedException; use OCA\EmailRecovery\Exception\RecoveryEmailAlreadyFoundException; use OCA\EmailRecovery\Exception\SameRecoveryEmailAsEmailException; use OCA\EmailRecovery\Exception\TooManyVerificationAttemptsException; -use OCA\EmailRecovery\Db\RecoveryMapper; - +use OCA\EmailRecovery\Db\ConfigMapper; use OCP\Defaults; use OCP\IConfig; use OCP\IL10N; @@ -42,7 +41,7 @@ class RecoveryEmailService { private ICacheFactory $cacheFactory; private CurlService $curl; private IClientService $httpClientService; - private RecoveryMapper $recoveryMapper; + private ConfigMapper $configMapper; private array $apiConfig; protected const TOKEN_LIFETIME = 60 * 30; // 30 minutes private const ATTEMPT_KEY = "recovery_email_attempts"; @@ -56,7 +55,7 @@ class RecoveryEmailService { private IL10N $l; private ISession $session; - public function __construct(string $appName, ILogger $logger, IConfig $config, ISession $session, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken, CurlService $curlService, DomainService $domainService, IL10N $l, ICacheFactory $cacheFactory, IClientService $httpClientService, RecoveryMapper $recoveryMapper) { + public function __construct(string $appName, ILogger $logger, IConfig $config, ISession $session, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken, CurlService $curlService, DomainService $domainService, IL10N $l, ICacheFactory $cacheFactory, IClientService $httpClientService, ConfigMapper $configMapper) { $this->logger = $logger; $this->config = $config; $this->appName = $appName; @@ -73,7 +72,7 @@ class RecoveryEmailService { $this->l = $l; $this->cacheFactory = $cacheFactory; // Initialize the cache factory $this->cache = $this->cacheFactory->createDistributed(self::CACHE_KEY); // Initialize the cache - $this->recoveryMapper = $recoveryMapper; + $this->configMapper = $configMapper; $commonServiceURL = $this->config->getSystemValue('common_services_url', ''); if (!empty($commonServiceURL)) { @@ -382,8 +381,8 @@ class RecoveryEmailService { return false; } - $usersWithEmailRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); - $usersWithUnverifiedRecovery = $this->recoveryMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); + $usersWithEmailRecovery = $this->configMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); + $usersWithUnverifiedRecovery = $this->configMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > $emailAliasLimit) { return true; } -- GitLab From 35021fddfa7f2c0d01cb238f66d853e19e23f8dc Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 13:27:11 +0200 Subject: [PATCH 12/26] method signature --- lib/Service/RecoveryEmailService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 5fab3ff..d957cd5 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -349,7 +349,7 @@ class RecoveryEmailService { return false; } - private function getPrefixAndDomainEmail(string $email) { + private function getPrefixAndDomain(string $email) : bool|array { if (!str_contains($email, '+')) { return false; } @@ -362,7 +362,7 @@ class RecoveryEmailService { } public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { - $recoveryEmailParts = $this->getPrefixAndDomainEmail($recoveryEmail); + $recoveryEmailParts = $this->getPrefixAndDomain($recoveryEmail); if (!$recoveryEmailParts) { return false; } -- GitLab From 1b17d16011dddfada8c180226ec929a49835df32 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 13:50:51 +0200 Subject: [PATCH 13/26] use QueryBuilder --- lib/Db/ConfigMapper.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/Db/ConfigMapper.php b/lib/Db/ConfigMapper.php index 86c92f9..a791ff9 100644 --- a/lib/Db/ConfigMapper.php +++ b/lib/Db/ConfigMapper.php @@ -7,22 +7,27 @@ use OCP\IDBConnection; class ConfigMapper { /** @var IDBConnection */ private $connection; + private $appName; - public function __construct(IDBConnection $connection) { + public function __construct(string $appName, IDBConnection $connection) { $this->connection = $connection; + $this->appName = $appName; } - public function getUsersForUserValue($appName, $key, $value) { - $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' . - 'WHERE `appid` = ? AND `configkey` = ? AND `configvalue` like ?'; - $result = $this->connection->executeQuery($sql, [$appName, $key, $value]); + public function getUsersByRecoveryEmail(string $pattern) { + $qb = $this->connection->getQueryBuilder(); + $qb->select('userid') + ->from("preferences")->where('configvalue` like :pattern AND (`configkey` = `unverified-recovery-email` OR `configkey` = `recovery-email`) AND `appid` = :appname ') + ->setParameter('pattern', $pattern) + ->setParameter('appname', $this->appName); + $result = $qb->execute(); $userIDs = []; while ($row = $result->fetch()) { $userIDs[] = $row['userid']; } - return $userIDs; } + } -- GitLab From 92741211a2842bab73110fd90fdc6bfe241f31fd Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 14:15:52 +0200 Subject: [PATCH 14/26] switch to isAliasedRecoveryEmailValid --- lib/Service/RecoveryEmailService.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index d957cd5..8489868 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -184,7 +184,7 @@ class RecoveryEmailService { throw new RecoveryEmailAlreadyFoundException($l->t('Recovery email address is already taken.')); } - if ($this->isRecoveryExtendedEmailAbused($username, $recoveryEmail)) { + if (!$this->isAliasedRecoveryEmailValid($username, $recoveryEmail)) { $this->logger->info("User ID $username's requested recovery extended email address is already taken"); throw new RecoveryEmailAlreadyFoundException($l->t('This email address in invalid, please use another one.')); } @@ -361,14 +361,14 @@ class RecoveryEmailService { return [$emailPrefix, $mailDomain]; } - public function isRecoveryExtendedEmailAbused(string $username, string $recoveryEmail): bool { + public function isAliasedRecoveryEmailValid(string $username, string $recoveryEmail): bool { $recoveryEmailParts = $this->getPrefixAndDomain($recoveryEmail); if (!$recoveryEmailParts) { - return false; + return true; } $emailAliasLimit = $this->config->getSystemValue('email_alias_limit', '5'); if($emailAliasLimit == -1) { - return false; + return true; } $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; $currentRecoveryEmail = $this->getRecoveryEmail($username); @@ -378,16 +378,15 @@ class RecoveryEmailService { if ($currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] || $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { - return false; + return true; } - $usersWithEmailRecovery = $this->configMapper->getUsersForUserValue($this->appName, 'recovery-email', $recoveryEmailregex); - $usersWithUnverifiedRecovery = $this->configMapper->getUsersForUserValue($this->appName, 'unverified-recovery-email', $recoveryEmailregex); - if (count($usersWithUnverifiedRecovery) + count($usersWithEmailRecovery) > $emailAliasLimit) { - return true; + $usersWithEmailRecovery = $this->configMapper->getUsersByRecoveryEmail($recoveryEmailregex); + if (count($usersWithEmailRecovery) > $emailAliasLimit) { + return false; } - return false; + return true; } public function updateRecoveryEmail(string $username, string $recoveryEmail) : void { -- GitLab From 95358dc6cf11f9d81cc2f5d9bf98f69a40b785eb Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 14:21:43 +0200 Subject: [PATCH 15/26] username instead of prefix --- lib/Service/RecoveryEmailService.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 8489868..9bfa9a1 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -349,20 +349,20 @@ class RecoveryEmailService { return false; } - private function getPrefixAndDomain(string $email) : bool|array { + private function getUsernameAndDomain(string $email) : bool|array { if (!str_contains($email, '+')) { return false; } $email = strtolower($email); $emailParts = explode('@', $email); - $emailPartsPlus = explode('+', $emailParts[0]); - $emailPrefix = $emailPartsPlus[0]; + $mailUsernameParts = explode('+', $emailParts[0]); + $mailUsername = $mailUsernameParts[0]; $mailDomain = $emailParts[1]; - return [$emailPrefix, $mailDomain]; + return [$mailUsername, $mailDomain]; } public function isAliasedRecoveryEmailValid(string $username, string $recoveryEmail): bool { - $recoveryEmailParts = $this->getPrefixAndDomain($recoveryEmail); + $recoveryEmailParts = $this->getUsernameAndDomain($recoveryEmail); if (!$recoveryEmailParts) { return true; } @@ -373,8 +373,8 @@ class RecoveryEmailService { $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; $currentRecoveryEmail = $this->getRecoveryEmail($username); $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); - $currentRecoveryEmailParts = $this->getPrefixAndDomainEmail($currentRecoveryEmail); - $currentUnverifiedRecoveryEmailParts = $this->getPrefixAndDomainEmail($currentUnverifiedRecoveryEmail); + $currentRecoveryEmailParts = $this->getUsernameAndDomain($currentRecoveryEmail); + $currentUnverifiedRecoveryEmailParts = $this->getUsernameAndDomain($currentUnverifiedRecoveryEmail); if ($currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] || $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { -- GitLab From 1297d9dabe67984504c5a71c145c8d400ad1943f Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 14:27:09 +0200 Subject: [PATCH 16/26] lint --- lib/Db/ConfigMapper.php | 1 - lib/Service/RecoveryEmailService.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Db/ConfigMapper.php b/lib/Db/ConfigMapper.php index a791ff9..1a00ba4 100644 --- a/lib/Db/ConfigMapper.php +++ b/lib/Db/ConfigMapper.php @@ -29,5 +29,4 @@ class ConfigMapper { } return $userIDs; } - } diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 9bfa9a1..49285a2 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -367,7 +367,7 @@ class RecoveryEmailService { return true; } $emailAliasLimit = $this->config->getSystemValue('email_alias_limit', '5'); - if($emailAliasLimit == -1) { + if ($emailAliasLimit == -1) { return true; } $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; -- GitLab From 571e2bad9b91c6362973160ded1f1272778ee2e9 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 16:07:38 +0200 Subject: [PATCH 17/26] fix query --- lib/Db/ConfigMapper.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Db/ConfigMapper.php b/lib/Db/ConfigMapper.php index 1a00ba4..87d292f 100644 --- a/lib/Db/ConfigMapper.php +++ b/lib/Db/ConfigMapper.php @@ -18,10 +18,9 @@ class ConfigMapper { public function getUsersByRecoveryEmail(string $pattern) { $qb = $this->connection->getQueryBuilder(); $qb->select('userid') - ->from("preferences")->where('configvalue` like :pattern AND (`configkey` = `unverified-recovery-email` OR `configkey` = `recovery-email`) AND `appid` = :appname ') + ->from("preferences")->where('`configvalue` like :pattern AND (`configkey` = "unverified-recovery-email" OR `configkey` = "recovery-email") AND `appid` = :appname ') ->setParameter('pattern', $pattern) ->setParameter('appname', $this->appName); - $result = $qb->execute(); $userIDs = []; while ($row = $result->fetch()) { -- GitLab From 3e3f2378291d3096233a9b6777c452939ca2bd90 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Fri, 25 Apr 2025 16:55:36 +0200 Subject: [PATCH 18/26] remove dots of gmail addresses --- lib/Service/RecoveryEmailService.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 49285a2..0c14ee5 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -353,10 +353,13 @@ class RecoveryEmailService { if (!str_contains($email, '+')) { return false; } - $email = strtolower($email); + $email = strtolower($email); $emailParts = explode('@', $email); $mailUsernameParts = explode('+', $emailParts[0]); $mailUsername = $mailUsernameParts[0]; + if(str_ends_with($email, "@gmail.com"){ + $mailUsername = str_replace(".","", $mailUsername); //remove dots for gmail addresses + } $mailDomain = $emailParts[1]; return [$mailUsername, $mailDomain]; } -- GitLab From 5ac6dfbcc3685f0defe55c96a2ff91f2959255bd Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Mon, 28 Apr 2025 10:44:44 +0200 Subject: [PATCH 19/26] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Akhil --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 0c14ee5..fbd777a 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -370,7 +370,7 @@ class RecoveryEmailService { return true; } $emailAliasLimit = $this->config->getSystemValue('email_alias_limit', '5'); - if ($emailAliasLimit == -1) { + if ($emailAliasLimit === -1) { return true; } $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; -- GitLab From b16744d8f3dc924918abab26d35a959877666a32 Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Mon, 28 Apr 2025 14:55:42 +0200 Subject: [PATCH 20/26] Revert "remove dots of gmail addresses" This reverts commit 3e3f2378291d3096233a9b6777c452939ca2bd90 --- lib/Service/RecoveryEmailService.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index fbd777a..29c4e99 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -353,13 +353,10 @@ class RecoveryEmailService { if (!str_contains($email, '+')) { return false; } - $email = strtolower($email); + $email = strtolower($email); $emailParts = explode('@', $email); $mailUsernameParts = explode('+', $emailParts[0]); $mailUsername = $mailUsernameParts[0]; - if(str_ends_with($email, "@gmail.com"){ - $mailUsername = str_replace(".","", $mailUsername); //remove dots for gmail addresses - } $mailDomain = $emailParts[1]; return [$mailUsername, $mailDomain]; } -- GitLab From dc1eed5eee8af51a8f7a9ef7bcf583348ea59cac Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Mon, 28 Apr 2025 14:56:20 +0200 Subject: [PATCH 21/26] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Akhil --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 29c4e99..03f28b7 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -366,7 +366,7 @@ class RecoveryEmailService { if (!$recoveryEmailParts) { return true; } - $emailAliasLimit = $this->config->getSystemValue('email_alias_limit', '5'); + $emailAliasLimit = (int) $this->config->getSystemValue('recovery_email_alias_limit', 5); if ($emailAliasLimit === -1) { return true; } -- GitLab From 242dfcd1e9e115a4089899686729702d143b33a2 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Mon, 28 Apr 2025 15:09:01 +0200 Subject: [PATCH 22/26] handle case where no recovery mail was set at first --- lib/Service/RecoveryEmailService.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 03f28b7..f9345e7 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -349,9 +349,9 @@ class RecoveryEmailService { return false; } - private function getUsernameAndDomain(string $email) : bool|array { - if (!str_contains($email, '+')) { - return false; + private function getUsernameAndDomain(string $email) : array { + if($email === null || empty($email)){ + return null; } $email = strtolower($email); $emailParts = explode('@', $email); @@ -362,10 +362,10 @@ class RecoveryEmailService { } public function isAliasedRecoveryEmailValid(string $username, string $recoveryEmail): bool { - $recoveryEmailParts = $this->getUsernameAndDomain($recoveryEmail); - if (!$recoveryEmailParts) { + if (!str_contains($recoveryEmail, '+')) { return true; } + $recoveryEmailParts = $this->getUsernameAndDomain($recoveryEmail); $emailAliasLimit = (int) $this->config->getSystemValue('recovery_email_alias_limit', 5); if ($emailAliasLimit === -1) { return true; @@ -376,8 +376,8 @@ class RecoveryEmailService { $currentRecoveryEmailParts = $this->getUsernameAndDomain($currentRecoveryEmail); $currentUnverifiedRecoveryEmailParts = $this->getUsernameAndDomain($currentUnverifiedRecoveryEmail); - if ($currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] - || $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { + if ($currentRecoveryEmailParts !== null && $currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] + || $currentUnverifiedRecoveryEmailParts !== null $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { return true; } -- GitLab From b6a86886a031ab6f9753e0352a4d7f3f03025894 Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Mon, 28 Apr 2025 16:36:48 +0200 Subject: [PATCH 23/26] mistake --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index f9345e7..243dc14 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -377,7 +377,7 @@ class RecoveryEmailService { $currentUnverifiedRecoveryEmailParts = $this->getUsernameAndDomain($currentUnverifiedRecoveryEmail); if ($currentRecoveryEmailParts !== null && $currentRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentRecoveryEmailParts[1] === $recoveryEmailParts[1] - || $currentUnverifiedRecoveryEmailParts !== null $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { + || $currentUnverifiedRecoveryEmailParts !== null && $currentUnverifiedRecoveryEmailParts[0] === $recoveryEmailParts[0] && $currentUnverifiedRecoveryEmailParts[1] === $recoveryEmailParts[1]) { return true; } -- GitLab From ea6b242c12751cf02c7aef95ef1a51a64af581ab Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Tue, 29 Apr 2025 09:25:24 +0200 Subject: [PATCH 24/26] nullable --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 243dc14..7ee3296 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -349,7 +349,7 @@ class RecoveryEmailService { return false; } - private function getUsernameAndDomain(string $email) : array { + private function getUsernameAndDomain(string $email) : ?array { if($email === null || empty($email)){ return null; } -- GitLab From cb2404f3e30ab41c95f8cebf8b87b4b61abd82af Mon Sep 17 00:00:00 2001 From: Alexandre R D'anzi Date: Tue, 29 Apr 2025 10:08:33 +0200 Subject: [PATCH 25/26] lint --- lib/Service/RecoveryEmailService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 7ee3296..ef139b4 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -350,7 +350,7 @@ class RecoveryEmailService { } private function getUsernameAndDomain(string $email) : ?array { - if($email === null || empty($email)){ + if ($email === null || empty($email)) { return null; } $email = strtolower($email); -- GitLab From 495e8d59bbf8366c9c00ccd08a2dd194396a2589 Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Tue, 29 Apr 2025 13:29:00 +0200 Subject: [PATCH 26/26] return type --- lib/Db/ConfigMapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Db/ConfigMapper.php b/lib/Db/ConfigMapper.php index 87d292f..6267174 100644 --- a/lib/Db/ConfigMapper.php +++ b/lib/Db/ConfigMapper.php @@ -15,7 +15,7 @@ class ConfigMapper { } - public function getUsersByRecoveryEmail(string $pattern) { + public function getUsersByRecoveryEmail(string $pattern) : array { $qb = $this->connection->getQueryBuilder(); $qb->select('userid') ->from("preferences")->where('`configvalue` like :pattern AND (`configkey` = "unverified-recovery-email" OR `configkey` = "recovery-email") AND `appid` = :appname ') -- GitLab