Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
]
);
}
Expand All @@ -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,
];
Expand All @@ -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
Expand All @@ -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'])) {
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion app/Services/SecurityPolicies/LockUserCounterMeasure.php
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 0 additions & 1 deletion app/libs/Auth/Factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions app/libs/Auth/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
Expand Down Expand Up @@ -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)
Expand Down
53 changes: 48 additions & 5 deletions resources/js/login/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ const PasswordInputForm = ({
captchaPublicKey,
onChangeRecaptcha,
handleEmitOtpAction,
forgotPasswordAction
forgotPasswordAction,
loginAttempts,
maxLoginFailedAttempts,
userIsActive
}) => {
return (
<form method="post" action={formAction} onSubmit={onAuthenticate} target="_self">
Expand Down Expand Up @@ -114,9 +117,46 @@ const PasswordInputForm = ({
)
}}
/>
{passwordError &&
<p className={styles.error_label} dangerouslySetInnerHTML={{__html: passwordError}}></p>
}
{(() => {
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 (
<>
<p className={styles.error_label}>
Incorrect password. You have {attemptsLeft} more attempt{attemptsLeft !== 1 ? 's' : ''} before your account is locked.
</p>
</>
);
}

if (attempts > 0 && attempts === maxAttempts && userIsActive) {
return (
<>
<p className={styles.error_label}>
Incorrect password. You have reached the maximum ({maxAttempts}) login attempts. Your account will be locked after another failed login.
</p>
</>
);
}

if (attempts > 0 && attempts === maxAttempts && !userIsActive) {
return (
<>
<p className={styles.error_label}>
Your account has been locked due to multiple failed login attempts. Please contact support to unlock it.
</p>
</>
);
}

return <p className={styles.error_label} dangerouslySetInnerHTML={{__html: passwordError}}></p>;
})()}

<Grid container spacing={1}>
<Grid item xs={12}>
<Button variant="contained"
Expand Down Expand Up @@ -434,7 +474,7 @@ class LoginPage extends React.Component {
this.resendVerificationEmail = this.resendVerificationEmail.bind(this);
this.handleSnackbarClose = this.handleSnackbarClose.bind(this);
this.showAlert = this.showAlert.bind(this);
}
}

showAlert(message, severity) {
this.setState({
Expand Down Expand Up @@ -776,6 +816,9 @@ class LoginPage extends React.Component {
onChangeRecaptcha={this.onChangeRecaptcha}
handleEmitOtpAction={this.handleEmitOtpAction}
forgotPasswordAction={this.props.forgotPasswordAction}
loginAttempts={this.props?.loginAttempts}
maxLoginFailedAttempts={this.props?.maxLoginFailedAttempts}
userIsActive={this.props?.user_is_active}
/>
<HelpLinks
userName={this.state.user_name}
Expand Down
18 changes: 13 additions & 5 deletions resources/views/auth/login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,35 @@
config.maxLoginAttempts2ShowCaptcha = {{Session::get("max_login_attempts_2_show_captcha")}};
@endif

@if(Session::has('max_login_failed_attempts'))
config.maxLoginFailedAttempts = {{Session::get("max_login_failed_attempts")}};
@endif

@if(Session::has('login_attempts'))
config.loginAttempts = {{Session::get("login_attempts")}};
@endif

@if(Session::has('user_is_active'))
config.user_is_active = {{Session::get("user_is_active")}};
@endif

@if(Session::has('user_fullname'))
config.user_fullname = '{{Session::get("user_fullname")}}';
@endif

@if(Session::has('user_pic'))
config.user_pic = '{{Session::get("user_pic")}}';
@endif
@if(Session::has('user_verified'))
@if(Session::has('user_verified'))
config.user_verified = {{Session::get('user_verified')}};
@endif
@if(Session::has('flow'))
@if(Session::has('flow'))
config.flow = '{{Session::get('flow')}}';
@endif

window.VERIFY_ACCOUNT_ENDPOINT = config.accountVerifyAction;
window.EMIT_OTP_ENDPOINT = config.emitOtpAction;
window.RESEND_VERIFICATION_EMAIL_ENDPOINT = config.resendVerificationEmailAction;
window.VERIFY_ACCOUNT_ENDPOINT = config.accountVerifyAction;
window.EMIT_OTP_ENDPOINT = config.emitOtpAction;
window.RESEND_VERIFICATION_EMAIL_ENDPOINT = config.resendVerificationEmailAction;
</script>
{!! script_to('assets/login.js') !!}
@append