mirror of
https://github.com/delight-im/PHP-Auth.git
synced 2025-08-07 00:26:28 +02:00
Extract usages of hashing for tokens to new class 'TokenHash'
This commit is contained in:
20
src/Auth.php
20
src/Auth.php
@@ -126,7 +126,7 @@ final class Auth extends UserManager {
|
|||||||
|
|
||||||
if (!empty($rememberData)) {
|
if (!empty($rememberData)) {
|
||||||
if ($rememberData['expires'] >= \time()) {
|
if ($rememberData['expires'] >= \time()) {
|
||||||
if (\password_verify($parts[1], $rememberData['token'])) {
|
if (TokenHash::verify($parts[1], $rememberData['token'])) {
|
||||||
// the cookie and its contents have now been proven to be valid
|
// the cookie and its contents have now been proven to be valid
|
||||||
$valid = true;
|
$valid = true;
|
||||||
|
|
||||||
@@ -498,7 +498,7 @@ final class Auth extends UserManager {
|
|||||||
private function createRememberDirective($userId, $duration) {
|
private function createRememberDirective($userId, $duration) {
|
||||||
$selector = self::createRandomString(24);
|
$selector = self::createRandomString(24);
|
||||||
$token = self::createRandomString(32);
|
$token = self::createRandomString(32);
|
||||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
$tokenHashed = TokenHash::from($token);
|
||||||
$expires = \time() + ((int) $duration);
|
$expires = \time() + ((int) $duration);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -636,7 +636,7 @@ final class Auth extends UserManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($confirmationData)) {
|
if (!empty($confirmationData)) {
|
||||||
if (\password_verify($token, $confirmationData['token'])) {
|
if (TokenHash::verify($token, $confirmationData['token'])) {
|
||||||
if ($confirmationData['expires'] >= \time()) {
|
if ($confirmationData['expires'] >= \time()) {
|
||||||
// invalidate any potential outstanding password reset requests
|
// invalidate any potential outstanding password reset requests
|
||||||
try {
|
try {
|
||||||
@@ -823,7 +823,7 @@ final class Auth extends UserManager {
|
|||||||
$this->throttle([ 'provideOneTimePasswordAsSecondFactor', $this->getIpAddress() ], 5, 60 * 15, 3);
|
$this->throttle([ 'provideOneTimePasswordAsSecondFactor', $this->getIpAddress() ], 5, 60 * 15, 3);
|
||||||
|
|
||||||
$otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $_SESSION[self::SESSION_FIELD_AWAITING_2FA_USER_ID]);
|
$otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $_SESSION[self::SESSION_FIELD_AWAITING_2FA_USER_ID]);
|
||||||
$otpValueToken = \password_hash($otpValue, \PASSWORD_DEFAULT);
|
$otpValueToken = TokenHash::from($otpValue);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$otpRecords = $this->db->select(
|
$otpRecords = $this->db->select(
|
||||||
@@ -841,7 +841,7 @@ final class Auth extends UserManager {
|
|||||||
if (!empty($otpRecords)) {
|
if (!empty($otpRecords)) {
|
||||||
foreach ($otpRecords as $otpRecord) {
|
foreach ($otpRecords as $otpRecord) {
|
||||||
if (!empty($otpRecord)) {
|
if (!empty($otpRecord)) {
|
||||||
if (\password_verify($otpValue, $otpRecord['token'])) {
|
if (TokenHash::verify($otpValue, $otpRecord['token'])) {
|
||||||
// if the mechanism for this one-time password was time-based (TOTP)
|
// if the mechanism for this one-time password was time-based (TOTP)
|
||||||
if (!empty($otpRecord['mechanism']) && ((int) $otpRecord['mechanism']) === self::TWO_FACTOR_MECHANISM_TOTP) {
|
if (!empty($otpRecord['mechanism']) && ((int) $otpRecord['mechanism']) === self::TWO_FACTOR_MECHANISM_TOTP) {
|
||||||
// if the one-time password had an expiry time and that time has passed recently
|
// if the one-time password had an expiry time and that time has passed recently
|
||||||
@@ -1381,7 +1381,7 @@ final class Auth extends UserManager {
|
|||||||
|
|
||||||
// create a selector/token pair from the generated one-time password
|
// create a selector/token pair from the generated one-time password
|
||||||
$otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $userId);
|
$otpValueSelector = self::createSelectorForOneTimePassword($otpValue, $userId);
|
||||||
$otpValueToken = \password_hash($otpValue, \PASSWORD_DEFAULT);
|
$otpValueToken = TokenHash::from($otpValue);
|
||||||
|
|
||||||
// store the generated one-time password for the user and define it to expire after ten minutes
|
// store the generated one-time password for the user and define it to expire after ten minutes
|
||||||
try {
|
try {
|
||||||
@@ -1494,7 +1494,7 @@ final class Auth extends UserManager {
|
|||||||
private function createPasswordResetRequest($userId, $expiresAfter, callable $callback) {
|
private function createPasswordResetRequest($userId, $expiresAfter, callable $callback) {
|
||||||
$selector = self::createRandomString(20);
|
$selector = self::createRandomString(20);
|
||||||
$token = self::createRandomString(20);
|
$token = self::createRandomString(20);
|
||||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
$tokenHashed = TokenHash::from($token);
|
||||||
$expiresAt = \time() + $expiresAfter;
|
$expiresAt = \time() + $expiresAfter;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1558,7 +1558,7 @@ final class Auth extends UserManager {
|
|||||||
|
|
||||||
if (!empty($resetData)) {
|
if (!empty($resetData)) {
|
||||||
if ((int) $resetData['resettable'] === 1) {
|
if ((int) $resetData['resettable'] === 1) {
|
||||||
if (\password_verify($token, $resetData['token'])) {
|
if (TokenHash::verify($token, $resetData['token'])) {
|
||||||
if ($resetData['expires'] >= \time()) {
|
if ($resetData['expires'] >= \time()) {
|
||||||
$newPassword = self::validatePassword($newPassword, true);
|
$newPassword = self::validatePassword($newPassword, true);
|
||||||
$this->updatePasswordInternal($resetData['user'], $newPassword);
|
$this->updatePasswordInternal($resetData['user'], $newPassword);
|
||||||
@@ -2100,7 +2100,7 @@ final class Auth extends UserManager {
|
|||||||
if (!empty($otpRecords)) {
|
if (!empty($otpRecords)) {
|
||||||
foreach ($otpRecords as $otpRecord) {
|
foreach ($otpRecords as $otpRecord) {
|
||||||
if (!empty($otpRecord)) {
|
if (!empty($otpRecord)) {
|
||||||
if (\password_verify($otpValue, $otpRecord['token'])) {
|
if (TokenHash::verify($otpValue, $otpRecord['token'])) {
|
||||||
$otpValueVerified = true;
|
$otpValueVerified = true;
|
||||||
|
|
||||||
// remove the one-time password from the database to prevent repeated usages
|
// remove the one-time password from the database to prevent repeated usages
|
||||||
@@ -2138,7 +2138,7 @@ final class Auth extends UserManager {
|
|||||||
for ($i = 0; $i < 6; $i++) {
|
for ($i = 0; $i < 6; $i++) {
|
||||||
$recoveryCode = \strtoupper(\Delight\Otp\Otp::createSecret(\Delight\Otp\Otp::SHARED_SECRET_STRENGTH_LOW));
|
$recoveryCode = \strtoupper(\Delight\Otp\Otp::createSecret(\Delight\Otp\Otp::SHARED_SECRET_STRENGTH_LOW));
|
||||||
$recoveryCodeSelector = self::createSelectorForOneTimePassword($recoveryCode, $this->getUserId());
|
$recoveryCodeSelector = self::createSelectorForOneTimePassword($recoveryCode, $this->getUserId());
|
||||||
$recoveryCodeToken = \password_hash($recoveryCode, \PASSWORD_DEFAULT);
|
$recoveryCodeToken = TokenHash::from($recoveryCode);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->db->insert(
|
$this->db->insert(
|
||||||
|
46
src/TokenHash.php
Normal file
46
src/TokenHash.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHP-Auth (https://github.com/delight-im/PHP-Auth)
|
||||||
|
* Copyright (c) delight.im (https://www.delight.im/)
|
||||||
|
* Licensed under the MIT License (https://opensource.org/licenses/MIT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Delight\Auth;
|
||||||
|
|
||||||
|
final class TokenHash {
|
||||||
|
|
||||||
|
const HASH_ALGORITHM_IDENTIFIER = \PASSWORD_DEFAULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a computationally expensive hash from a token
|
||||||
|
*
|
||||||
|
* @param string $tokenText
|
||||||
|
* @return string|bool
|
||||||
|
*/
|
||||||
|
public static function from($tokenText) {
|
||||||
|
return \password_hash($tokenText, self::HASH_ALGORITHM_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies whether a token matches a computationally expensive hash
|
||||||
|
*
|
||||||
|
* @param string $tokenText
|
||||||
|
* @param string $expectedHash
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function verify($tokenText, $expectedHash) {
|
||||||
|
return \password_verify($tokenText, $expectedHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a computationally expensive hash needs to be updated to match a desired algorithm and set of options
|
||||||
|
*
|
||||||
|
* @param string $existingHash
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function needsRehash($existingHash) {
|
||||||
|
return \password_needs_rehash($existingHash, self::HASH_ALGORITHM_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -359,7 +359,7 @@ abstract class UserManager {
|
|||||||
protected function createConfirmationRequest($userId, $email, callable $callback) {
|
protected function createConfirmationRequest($userId, $email, callable $callback) {
|
||||||
$selector = self::createRandomString(16);
|
$selector = self::createRandomString(16);
|
||||||
$token = self::createRandomString(16);
|
$token = self::createRandomString(16);
|
||||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
$tokenHashed = TokenHash::from($token);
|
||||||
$expires = \time() + 60 * 60 * 24;
|
$expires = \time() + 60 * 60 * 24;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user