diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 599a4c49..5b52d7aa 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -393,6 +393,7 @@ public function resendVerificationEmail(LaravelRequest $request) public function postLogin() { $max_login_attempts_2_show_captcha = $this->server_configuration_service->getConfigValue("MaxFailed.LoginAttempts.2ShowCaptcha"); + $max_login_failed_attempts = intval($this->server_configuration_service->getConfigValue("MaxFailed.Login.Attempts")); $login_attempts = 0; $username = ''; $user = null; @@ -479,13 +480,15 @@ public function postLogin() ( [ 'max_login_attempts_2_show_captcha' => $max_login_attempts_2_show_captcha, + 'max_login_failed_attempts' => $max_login_failed_attempts, 'login_attempts' => $login_attempts, 'error_message' => $ex->getMessage(), 'user_fullname' => !is_null($user) ? $user->getFullName() : "", 'user_pic' => !is_null($user) ? $user->getPic(): "", 'user_verified' => true, 'username' => $username, - 'flow' => $flow + 'flow' => $flow, + 'user_is_active' => !is_null($user) ? ($user->isActive() ? 1 : 0) : 0 ] ); } @@ -495,6 +498,7 @@ public function postLogin() // validator errors $response_data = [ 'max_login_attempts_2_show_captcha' => $max_login_attempts_2_show_captcha, + 'max_login_failed_attempts' => $max_login_failed_attempts, 'login_attempts' => $login_attempts, 'validator' => $validator, ]; @@ -506,7 +510,8 @@ public function postLogin() if(!is_null($user)){ $response_data['user_fullname'] = $user->getFullName(); $response_data['user_pic'] = $user->getPic(); - $response_data['user_verified'] = true; + $response_data['user_verified'] = 1; + $response_data['user_is_active'] = $user->isActive() ? 1 : 0; } return $this->login_strategy->errorLogin @@ -521,9 +526,10 @@ public function postLogin() $response_data = [ 'max_login_attempts_2_show_captcha' => $max_login_attempts_2_show_captcha, + 'max_login_failed_attempts' => $max_login_failed_attempts, 'login_attempts' => $login_attempts, 'username' => $username, - 'error_message' => $ex1->getMessage() + 'error_message' => $ex1->getMessage(), ]; if (is_null($user) && isset($data['username'])) { @@ -533,7 +539,8 @@ public function postLogin() if(!is_null($user)){ $response_data['user_fullname'] = $user->getFullName(); $response_data['user_pic'] = $user->getPic(); - $response_data['user_verified'] = true; + $response_data['user_verified'] = 1; + $response_data['user_is_active'] = $user->isActive() ? 1 : 0; } return $this->login_strategy->errorLogin diff --git a/app/Services/SecurityPolicies/LockUserCounterMeasure.php b/app/Services/SecurityPolicies/LockUserCounterMeasure.php index fc310094..b38df7b3 100644 --- a/app/Services/SecurityPolicies/LockUserCounterMeasure.php +++ b/app/Services/SecurityPolicies/LockUserCounterMeasure.php @@ -77,7 +77,7 @@ public function trigger(array $params = []) $user_id = $params["user_id"]; $user = $this->repository->getById($user_id); $max_login_failed_attempts = intval($this->server_configuration->getConfigValue("MaxFailed.Login.Attempts")); - if (!is_null($user) && $user instanceof User) { + if ($user instanceof User) { //apply lock policy if (intval($user->getLoginFailedAttempt()) < $max_login_failed_attempts) { $this->user_service->updateFailedLoginAttempts($user->getId()); diff --git a/app/libs/Auth/Factories/UserFactory.php b/app/libs/Auth/Factories/UserFactory.php index 5602116c..b0ca3027 100644 --- a/app/libs/Auth/Factories/UserFactory.php +++ b/app/libs/Auth/Factories/UserFactory.php @@ -11,7 +11,6 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use Auth\Group; use Auth\User; use Illuminate\Support\Facades\Auth; diff --git a/app/libs/Auth/Models/User.php b/app/libs/Auth/Models/User.php index b04b5d13..23f98918 100644 --- a/app/libs/Auth/Models/User.php +++ b/app/libs/Auth/Models/User.php @@ -1854,6 +1854,8 @@ public function activate():void { if(!$this->active) { $this->active = true; $this->spam_type = self::SpamTypeHam; + // reset it + $this->login_failed_attempt = 0; Event::dispatch(new UserSpamStateUpdated( $this->getId() ) @@ -1886,6 +1888,7 @@ public function verifyEmail(bool $send_email_verified_notice = true) $this->spam_type = self::SpamTypeHam; $this->active = true; $this->lock = false; + $this->login_failed_attempt = 0; $this->email_verified_date = new \DateTime('now', new \DateTimeZone('UTC')); if($send_email_verified_notice) diff --git a/resources/js/login/login.js b/resources/js/login/login.js index 323095bf..2b3f6791 100644 --- a/resources/js/login/login.js +++ b/resources/js/login/login.js @@ -82,7 +82,10 @@ const PasswordInputForm = ({ captchaPublicKey, onChangeRecaptcha, handleEmitOtpAction, - forgotPasswordAction + forgotPasswordAction, + loginAttempts, + maxLoginFailedAttempts, + userIsActive }) => { return (
@@ -114,9 +117,46 @@ const PasswordInputForm = ({ ) }} /> - {passwordError && -

- } + {(() => { + const attempts = parseInt(loginAttempts, 10); + const maxAttempts = parseInt(maxLoginFailedAttempts, 10); + const attemptsLeft = maxAttempts - attempts; + + if (!passwordError) return null; + + if (attempts > 0 && attempts < maxAttempts && userIsActive) { + return ( + <> +

+ Incorrect password. You have {attemptsLeft} more attempt{attemptsLeft !== 1 ? 's' : ''} before your account is locked. +

+ + ); + } + + if (attempts > 0 && attempts === maxAttempts && userIsActive) { + return ( + <> +

+ Incorrect password. You have reached the maximum ({maxAttempts}) login attempts. Your account will be locked after another failed login. +

+ + ); + } + + if (attempts > 0 && attempts === maxAttempts && !userIsActive) { + return ( + <> +

+ Your account has been locked due to multiple failed login attempts. Please contact support to unlock it. +

+ + ); + } + + return

; + })()} +