diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 958651a744b5a3ac716a21f58ff94610e1fa6cff..c0f8c7b21de7bff1868bbd65262b06d3a690ccb9 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 79b0c2f83d77723e8e9800f00774beb8610f92d7..ee6e86a28d467802a5dda7f5bf972185399abcc9 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 618b8a408acf3c97dce60593f94d3bd081e0f2b7..5478cf692f48ec20ea34ec3217b66cd944efafa3 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 fd067414bd301b9a18e9a236cde902f2c24c9a01..79d25d7c5a5261ecd32cc65c88f6547f4ba7a2b8 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 9124408a6bd8f9b52196ea6e99d83b8e61d98c51..1754bcfbb487813afb76da93f3b3fb6101203534 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 15b667e5c313821385dfe673d3b20e244cf7b0c4..ccb69996e42b6bdf942e1e16c3ec0e51a93d7210 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 35888db14663072841ff2d4deb16d741913fc270..1ed39f1bf7c4acd17f6e0ecacda1be0e7c53861b 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 5f0c7def02c7d0efee07b9ec8c94539c71137382..21e38a034ae1afd521fe3b2d6d5e33708e435e1c 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/Db/ConfigMapper.php b/lib/Db/ConfigMapper.php new file mode 100644 index 0000000000000000000000000000000000000000..62671745567de7aa2b9426e37f47cca1e204ec7d --- /dev/null +++ b/lib/Db/ConfigMapper.php @@ -0,0 +1,31 @@ +connection = $connection; + $this->appName = $appName; + } + + + 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 ') + ->setParameter('pattern', $pattern) + ->setParameter('appname', $this->appName); + $result = $qb->execute(); + $userIDs = []; + while ($row = $result->fetch()) { + $userIDs[] = $row['userid']; + } + return $userIDs; + } +} diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index e4532ff28eafad6f7210287777a6441704d44ab9..ef139b4005aae396444a2a48c4bf86c402abb86f 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -11,6 +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\ConfigMapper; use OCP\Defaults; use OCP\IConfig; use OCP\IL10N; @@ -40,6 +41,7 @@ class RecoveryEmailService { private ICacheFactory $cacheFactory; private CurlService $curl; private IClientService $httpClientService; + private ConfigMapper $configMapper; private array $apiConfig; protected const TOKEN_LIFETIME = 60 * 30; // 30 minutes private const ATTEMPT_KEY = "recovery_email_attempts"; @@ -53,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) { + 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; @@ -70,6 +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->configMapper = $configMapper; $commonServiceURL = $this->config->getSystemValue('common_services_url', ''); if (!empty($commonServiceURL)) { @@ -180,6 +183,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->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.')); + } if ($this->isRecoveryEmailDomainDisallowed($recoveryEmail)) { $this->logger->info("User ID $username's requested recovery email address is disallowed."); @@ -341,6 +349,46 @@ class RecoveryEmailService { return false; } + private function getUsernameAndDomain(string $email) : ?array { + if ($email === null || empty($email)) { + return null; + } + $email = strtolower($email); + $emailParts = explode('@', $email); + $mailUsernameParts = explode('+', $emailParts[0]); + $mailUsername = $mailUsernameParts[0]; + $mailDomain = $emailParts[1]; + return [$mailUsername, $mailDomain]; + } + + public function isAliasedRecoveryEmailValid(string $username, string $recoveryEmail): bool { + 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; + } + $recoveryEmailregex = $recoveryEmailParts[0]."+%@".$recoveryEmailParts[1]; + $currentRecoveryEmail = $this->getRecoveryEmail($username); + $currentUnverifiedRecoveryEmail = $this->getUnverifiedRecoveryEmail($username); + $currentRecoveryEmailParts = $this->getUsernameAndDomain($currentRecoveryEmail); + $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]) { + return true; + } + + $usersWithEmailRecovery = $this->configMapper->getUsersByRecoveryEmail($recoveryEmailregex); + if (count($usersWithEmailRecovery) > $emailAliasLimit) { + return false; + } + + return true; + } + public function updateRecoveryEmail(string $username, string $recoveryEmail) : void { $this->setUnverifiedRecoveryEmail($username, $recoveryEmail); $this->setRecoveryEmail($username, '');