diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 6c31f28754..e54dd3ef42 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -374,6 +374,13 @@ App::post('/v1/account') $passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; $password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + try { $userId = $userId == 'unique()' ? ID::unique() : $userId; $user->setAttributes([ @@ -402,7 +409,13 @@ App::post('/v1/account') 'authenticators' => null, 'search' => implode(' ', [$userId, $email, $name]), 'accessedAt' => DateTime::now(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); + $user->removeAttribute('$sequence'); $user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user)); try { @@ -1675,17 +1688,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') } if (empty($user->getAttribute('email'))) { - $oauth2Email = $oauth2->getUserEmail($accessToken); + $user->setAttribute('email', $oauth2->getUserEmail($accessToken)); - $emailCanonical = new EmailCanonical($oauth2Email); + try { + $emailCanonical = new EmailCanonical($user->getAttribute('email')); - $user - ->setAttribute('email', $oauth2Email) - ->setAttribute('emailCanonical', $emailCanonical->getCanonical()) - ->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()) - ->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()) - ->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()) - ->setAttribute('emailIsFree', $emailCanonical->isFree()); + $user->setAttribute('emailCanonical', $emailCanonical->getCanonical()); + $user->setAttribute('emailIsCanonical', $emailCanonical->isCanonicalSupported()); + $user->setAttribute('emailIsCorporate', $emailCanonical->isCorporate()); + $user->setAttribute('emailIsDisposable', $emailCanonical->isDisposable()); + $user->setAttribute('emailIsFree', $emailCanonical->isFree()); + } catch (Throwable) { + } } if (empty($user->getAttribute('name'))) { @@ -2230,7 +2244,11 @@ App::post('/v1/account/tokens/email') $userId = $userId === 'unique()' ? ID::unique() : $userId; - $emailCanonical = new EmailCanonical($email); + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } $user->setAttributes([ '$id' => $userId, @@ -2254,11 +2272,11 @@ App::post('/v1/account/tokens/email') 'memberships' => null, 'search' => implode(' ', [$userId, $email]), 'accessedAt' => DateTime::now(), - 'emailCanonical' => $emailCanonical->getCanonical(), - 'emailIsCanonical' => $emailCanonical->isCanonicalSupported(), - 'emailIsCorporate' => $emailCanonical->isCorporate(), - 'emailIsDisposable' => $emailCanonical->isDisposable(), - 'emailIsFree' => $emailCanonical->isFree(), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); $user->removeAttribute('$sequence'); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7398e451b5..cb956390b7 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -48,6 +48,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; +use Utopia\Emails\Email as EmailCanonical; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -564,6 +565,12 @@ App::post('/v1/teams/:teamId/memberships') throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } + try { + $emailCanonical = new EmailCanonical($email); + } catch (Throwable) { + $emailCanonical = null; + } + try { $userId = ID::unique(); $invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([ @@ -596,6 +603,11 @@ App::post('/v1/teams/:teamId/memberships') 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]))); } catch (Duplicate $th) { throw new Exception(Exception::USER_ALREADY_EXISTS); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 5498a33bf5..dccfec1101 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -49,6 +49,7 @@ use Utopia\Database\Validator\Query\Cursor; use Utopia\Database\Validator\Query\Limit; use Utopia\Database\Validator\Query\Offset; use Utopia\Database\Validator\UID; +use Utopia\Emails\Email as EmailCanonical; use Utopia\Locale\Locale; use Utopia\System\System; use Utopia\Validator\ArrayList; @@ -97,6 +98,12 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e } } + try { + $emailCanonical = new EmailCanonical($email ?? ''); + } catch (Throwable) { + $emailCanonical = null; + } + $password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null; $user = new Document([ '$id' => $userId, @@ -124,6 +131,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e 'tokens' => null, 'memberships' => null, 'search' => implode(' ', [$userId, $email, $phone, $name]), + 'emailCanonical' => $emailCanonical?->getCanonical(), + 'emailIsCanonical' => $emailCanonical?->isCanonicalSupported(), + 'emailIsCorporate' => $emailCanonical?->isCorporate(), + 'emailIsDisposable' => $emailCanonical?->isDisposable(), // todo: fix throw + 'emailIsFree' => $emailCanonical?->isFree(), // todo: fix throw ]); if ($hash === 'plaintext') {