From e266178f95f7d9cf8f492420a572c2c43a90d4dd Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 4 Apr 2024 19:09:40 +0200 Subject: [PATCH] Extract code into separate 'generateAndStoreRandomOneTimePassword' --- src/Auth.php | 73 ++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/Auth.php b/src/Auth.php index 53effd1..d307186 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -1320,28 +1320,7 @@ final class Auth extends UserManager { $throttled = true; } - // generate a one-time password - $otpValue = \strtoupper(\substr(\Delight\Otp\Otp::createSecret(\Delight\Otp\Otp::SHARED_SECRET_STRENGTH_LOW), 0, 6)); - $otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $userId); - $otpValueToken = \password_hash($otpValue, \PASSWORD_DEFAULT); - - // store the generated one-time password - try { - $this->db->insert( - $this->makeTableNameComponents('users_otps'), - [ - 'user_id' => $userId, - 'mechanism' => $twoFactorMethod['mechanism'], - 'single_factor' => 0, - 'selector' => $otpValueSelector, - 'token' => $otpValueToken, - 'expires_at' => \time() + 60 * 10, - ] - ); - } - catch (Error $e) { - throw new DatabaseError($e->getMessage()); - } + $otpValue = $this->generateAndStoreRandomOneTimePassword($userId, $twoFactorMethod['mechanism']); if ($twoFactorMethod['mechanism'] === self::TWO_FACTOR_MECHANISM_SMS) { $secondFactorRequiredException->addSmsOption($twoFactorMethod['seed'], $otpValue); @@ -1352,17 +1331,6 @@ final class Auth extends UserManager { else { throw new InvalidStateError(); } - - // delete any old one-time passwords for this user that have expired at least 15 minutes ago - try { - $this->db->exec( - 'DELETE FROM ' . $this->makeTableName('users_otps') . ' WHERE user_id = ? AND expires_at < ?', - [ $userId, \time() - 60 * 15 ] - ); - } - catch (Error $e) { - throw new DatabaseError($e->getMessage()); - } } // if the specific mechanism mandates that the one-time password is generated on the client side elseif ($twoFactorMethod['mechanism'] === self::TWO_FACTOR_MECHANISM_TOTP) { @@ -1392,6 +1360,45 @@ final class Auth extends UserManager { } } + private function generateAndStoreRandomOneTimePassword($userId, $mechanism) { + // generate a random one-time password + $otpLength = 6; + $otpValue = \strtoupper(\substr(\Delight\Otp\Otp::createSecret(\Delight\Otp\Otp::SHARED_SECRET_STRENGTH_LOW), 0, $otpLength)); + $otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $userId); + $otpValueToken = \password_hash($otpValue, \PASSWORD_DEFAULT); + + // store the generated one-time password for the user and define it to expire after ten minutes + try { + $this->db->insert( + $this->makeTableNameComponents('users_otps'), + [ + 'user_id' => $userId, + 'mechanism' => $mechanism, + 'single_factor' => 0, + 'selector' => $otpValueSelector, + 'token' => $otpValueToken, + 'expires_at' => \time() + 60 * 10, + ] + ); + } + catch (Error $e) { + throw new DatabaseError($e->getMessage()); + } + + // delete any old one-time passwords for the user that have expired at least 15 minutes ago + try { + $this->db->exec( + 'DELETE FROM ' . $this->makeTableName('users_otps') . ' WHERE user_id = ? AND expires_at < ?', + [ $userId, \time() - 60 * 15 ] + ); + } + catch (Error $e) { + throw new DatabaseError($e->getMessage()); + } + + return $otpValue; + } + /** * Returns the requested user data for the account with the specified email address (if any) *