From 0b1b7b817025709a784ae106bfd1c269c488dc49 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Fri, 16 Dec 2022 10:47:08 +0000 Subject: [PATCH] feat: check history limit --- app/controllers/api/account.php | 23 ++++++++++++++++------- app/controllers/api/projects.php | 2 +- app/controllers/api/users.php | 23 ++++++++++++++++------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 0b6423a6b..50b8460d4 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1509,24 +1509,33 @@ App::patch('/v1/account/password') ->param('oldPassword', '', new Password(), 'Current user password. Must be at least 8 chars.', true) ->inject('response') ->inject('user') + ->inject('project') ->inject('dbForProject') ->inject('events') - ->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Event $events) { + ->action(function (string $password, string $oldPassword, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) { // Check old password only if its an existing user. if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password throw new Exception(Exception::USER_INVALID_CREDENTIALS); } - $history = $user->getAttribute('passwordHistory', []); - $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + $historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; - if(in_array($newPassword, $history)) { - throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409); + $history = []; + if($historyLimit > 0) { + $history = $user->getAttribute('passwordHistory', []); + $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + + if(in_array($newPassword, $history)) { + throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409); + } + + $history[] = $newPassword; + while(count($history) > $historyLimit) { + array_pop($history); + } } - $history[] = $newPassword; - $user = $dbForProject->updateDocument('users', $user->getId(), $user ->setAttribute('passwordHistory', $history) ->setAttribute('password', $newPassword) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index e9425e8b6..ab741a797 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -81,7 +81,7 @@ App::post('/v1/projects') } $auth = Config::getParam('auth', []); - $auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG]; + $auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG]; foreach ($auth as $index => $method) { $auths[$method['key'] ?? ''] = true; } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 32c7735de..3974234d3 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -783,9 +783,10 @@ App::patch('/v1/users/:userId/password') ->param('userId', '', new UID(), 'User ID.') ->param('password', '', new Password(), 'New user password. Must be at least 8 chars.') ->inject('response') + ->inject('project') ->inject('dbForProject') ->inject('events') - ->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) { + ->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) { $user = $dbForProject->getDocument('users', $userId); @@ -793,15 +794,23 @@ App::patch('/v1/users/:userId/password') throw new Exception(Exception::USER_NOT_FOUND); } - $history = $user->getAttribute('passwordHistory', []); - $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + $historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0; - if(in_array($newPassword, $history)) { - throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409); + $history = []; + if($historyLimit > 0) { + $history = $user->getAttribute('passwordHistory', []); + $newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS); + + if(in_array($newPassword, $history)) { + throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409); + } + + $history[] = $newPassword; + while(count($history) > $historyLimit) { + array_pop($history); + } } - $history[] = $newPassword; - $user ->setAttribute('passwordHistory', $history) ->setAttribute('password', $newPassword)