Browse Source

UI: Redesigned 2fa login page

pull/6235/head
Vladyslav_Prykhodko 4 years ago
parent
commit
9c8913edb4
  1. 2
      ui-ngx/src/app/core/auth/auth.service.ts
  2. 18
      ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html
  3. 8
      ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.scss
  4. 34
      ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.ts
  5. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
ui-ngx/src/app/core/auth/auth.service.ts

@ -127,7 +127,7 @@ export class AuthService {
public checkTwoFaVerificationCode(providerType: TwoFactorAuthProviderType, verificationCode: number): Observable<LoginResponse> {
return this.http.post<LoginResponse>(`/api/auth/2fa/verification/check?providerType=${providerType}&verificationCode=${verificationCode}`,
null, defaultHttpOptions()).pipe(
null, defaultHttpOptions(false, true)).pipe(
tap((loginResponse: LoginResponse) => {
this.setUserFromJwtToken(loginResponse.token, loginResponse.refreshToken, true);
}

18
ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html

@ -46,9 +46,18 @@
[attr.inputmode]="inputMode" [pattern]="pattern"
autocomplete="off"
placeholder="{{ providersData.get(selectedProvider).placeholder | translate }}"/>
<mat-error *ngIf="verificationForm.get('verificationCode').invalid">
<mat-error *ngIf="verificationForm.get('verificationCode').getError('required') ||
verificationForm.get('verificationCode').getError('minlength') ||
verificationForm.get('verificationCode').getError('maxlength') ||
verificationForm.get('verificationCode').getError('pattern')">
{{ 'security.2fa.dialog.verification-code-invalid' | translate }}
</mat-error>
<mat-error *ngIf="verificationForm.get('verificationCode').getError('incorrectCode')">
{{ 'security.2fa.dialog.verification-code-incorrect' | translate }}
</mat-error>
<mat-error *ngIf="verificationForm.get('verificationCode').getError('tooManyRequest')">
{{ 'security.2fa.dialog.verification-code-many-request' | translate }}
</mat-error>
</mat-form-field>
</div>
<span style="height: 50px;"></span>
@ -59,12 +68,12 @@
{{ 'action.continue' | translate }}
</button>
<span style="height: 16px;"></span>
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="8px">
<div *ngIf="showResendButton" fxFlex="50" fxLayoutAlign="center center">
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="8px" class="action-row">
<div *ngIf="showResendAction" fxFlex fxLayoutAlign="center center" class="action-resend">
<div *ngIf="countDownTime" class="timer">
{{ 'login.resend-code-wait' | translate : {time: countDownTime} }}
</div>
<button *ngIf="!disabledResendButton"
<button [fxShow]="!hideResendButton"
mat-button fxFlex
(click)="sendCode($event)"
type="button">
@ -73,6 +82,7 @@
</div>
<button mat-button fxFlex
type="button"
*ngIf="allowProviders.length > 1"
(click)="selectProvider(null)">
{{ 'login.try-another-way' | translate }}
</button>

8
ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.scss

@ -60,6 +60,14 @@
font: 500 12px / 14px Roboto, "Helvetica Neue", sans-serif;
color: rgba(255, 255, 255, 0.8);
}
.action-row:nth-child(n) {
min-height: 36px;
.action-resend {
min-width: 50%;
}
}
}
}

34
ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.ts

@ -28,6 +28,7 @@ import {
} from '@shared/models/two-factor-auth.models';
import { TranslateService } from '@ngx-translate/core';
import { interval, Subscription } from 'rxjs';
import { isEqual } from '@core/utils';
@Component({
selector: 'tb-two-factor-auth-login',
@ -40,14 +41,15 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
private prevProvider: TwoFactorAuthProviderType;
private timer: Subscription;
private minVerificationPeriod = 0;
private timerID: NodeJS.Timeout;
showResendButton = false;
showResendAction = false;
selectedProvider: TwoFactorAuthProviderType;
allowProviders: TwoFactorAuthProviderType[] = [];
providersData = twoFactorAuthProvidersLoginData;
providerDescription = '';
disabledResendButton = true;
hideResendButton = true;
countDownTime = 0;
maxLengthInput = 6;
@ -88,7 +90,7 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
});
if (this.selectedProvider !== TwoFactorAuthProviderType.TOTP) {
this.sendCode();
this.showResendButton = true;
this.showResendAction = true;
}
this.timer = interval(1000).subscribe(() => this.updatedTime());
}
@ -96,12 +98,28 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
ngOnDestroy() {
super.ngOnDestroy();
this.timer.unsubscribe();
clearTimeout(this.timerID);
}
sendVerificationCode() {
if (this.verificationForm.valid && this.selectedProvider) {
this.authService.checkTwoFaVerificationCode(this.selectedProvider, this.verificationForm.get('verificationCode').value).subscribe(
() => {}
() => {},
(error) => {
if (error.status === 400) {
this.verificationForm.get('verificationCode').setErrors({incorrectCode: true});
} else if (error.status === 429) {
this.verificationForm.get('verificationCode').setErrors({tooManyRequest: true});
this.timerID = setTimeout(() => {
let errors = this.verificationForm.get('verificationCode').errors;
delete errors.tooManyRequest;
if (isEqual(errors, {})) {
errors = null;
}
this.verificationForm.get('verificationCode').setErrors(errors);
}, 5000);
}
}
);
}
}
@ -109,7 +127,7 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
selectProvider(type: TwoFactorAuthProviderType) {
this.prevProvider = type === null ? this.selectedProvider : null;
this.selectedProvider = type;
this.showResendButton = false;
this.showResendAction = false;
if (type !== null) {
this.verificationForm.get('verificationCode').reset();
const providerConfig = this.providersInfo.find(config => config.type === type);
@ -118,7 +136,7 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
});
if (type !== TwoFactorAuthProviderType.TOTP && type !== TwoFactorAuthProviderType.BACKUP_CODE) {
this.sendCode();
this.showResendButton = true;
this.showResendAction = true;
this.minVerificationPeriod = providerConfig?.minVerificationCodeSendPeriod || 30;
}
if (type === TwoFactorAuthProviderType.BACKUP_CODE) {
@ -150,7 +168,7 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
if ($event) {
$event.stopPropagation();
}
this.disabledResendButton = true;
this.hideResendButton = true;
this.twoFactorAuthService.requestTwoFaVerificationCodeSend(this.selectedProvider).subscribe(() => {
this.countDownTime = this.minVerificationPeriod;
}, () => {
@ -171,7 +189,7 @@ export class TwoFactorAuthLoginComponent extends PageComponent implements OnInit
if (this.countDownTime > 0) {
this.countDownTime--;
if (this.countDownTime === 0) {
this.disabledResendButton = false;
this.hideResendButton = false;
}
}
}

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2633,6 +2633,8 @@
"totp-step-label": "Get app",
"verification-code": "6-digit code",
"verification-code-invalid": "Invalid verification code format",
"verification-code-incorrect": "Verification code is incorrect",
"verification-code-many-request": "Too many requests check verification code",
"verification-step-description": "Enter a 6-digit code we just sent to {{address}}",
"verification-step-label": "Verification"
},

Loading…
Cancel
Save