diff --git a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.html index b5a06a6669..d50430cfe3 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.html @@ -38,7 +38,7 @@ {{ provider.value.providerType }} @@ -114,6 +114,17 @@ {{ 'admin.2fa.total-allowed-time-for-verification-pattern' | translate }} + + admin.2fa.retry-verification-code-period + + + {{ 'admin.2fa.retry-verification-code-period-required' | translate }} + + + {{ 'admin.2fa.retry-verification-code-period-pattern' | translate }} + + admin.2fa.max-verification-failures-before-user-lockout @@ -127,48 +138,11 @@ + - - - {{ 'admin.2fa.verification-code-send-rate-limit' | translate }} - - - -
- - admin.2fa.number-of-send-attempts - - - {{ 'admin.2fa.number-of-send-attempts-required' | translate }} - - - {{ 'admin.2fa.number-of-send-attempts-pattern' | translate }} - - - - admin.2fa.within-time - - - {{ 'admin.2fa.within-time-required' | translate }} - - - {{ 'admin.2fa.within-time-pattern' | translate }} - - -
-
-
- - - - - {{ 'admin.2fa.verification-code-check-rate-limit' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.scss index 8cef8aaf8d..e29f039fde 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.scss @@ -14,47 +14,55 @@ * limitations under the License. */ -:host{ +@import "../../../../../scss/constants"; - .fields-group { - margin: 8px 0; - border: 1px groove rgba(0, 0, 0, .25); - border-radius: 4px; - position: relative; - padding-bottom: 8px; +:host{ - legend { - color: rgba(0, 0, 0, .7); - width: fit-content; - margin: 0 8px; + mat-card.settings-card { + @media #{$mat-md} { + width: 90%; } - .input-row { - padding: 8px 8px 0; - } + .fields-group { + margin: 8px 0; + border: 1px groove rgba(0, 0, 0, .25); + border-radius: 4px; + position: relative; + padding-bottom: 8px; + + legend { + color: rgba(0, 0, 0, .7); + width: fit-content; + margin: 0 8px; + } + + .input-row { + padding: 8px 8px 0; + } - &:last-of-type { - margin-bottom: 24px; + &:last-of-type { + margin-bottom: 24px; + } } - } - .mat-expansion-panel { - box-shadow: none; - margin: 1px 0 0; - &.provider { - overflow: inherit; - .mat-expansion-panel-header { - padding: 0 24px 0 8px; - &.mat-expanded { - height: 48px; + .mat-expansion-panel { + box-shadow: none; + margin: 1px 0 0; + &.provider { + overflow: inherit; + .mat-expansion-panel-header { + padding: 0 24px 0 8px; + &.mat-expanded { + height: 48px; + } + .mat-slide-toggle { + margin-right: 8px; + } } - .mat-slide-toggle { - margin-right: 8px; + .mat-expansion-panel-header-title { + height: 40px; } } - .mat-expansion-panel-header-title { - height: 40px; - } } } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts index 18ac46c94d..bc2d936aa6 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts @@ -35,7 +35,7 @@ import { MatExpansionPanel } from '@angular/material/expansion'; @Component({ selector: 'tb-2fa-settings', templateUrl: './two-factor-auth-settings.component.html', - styleUrls: ['./two-factor-auth-settings.component.scss', './settings-card.scss'] + styleUrls: [ './settings-card.scss', './two-factor-auth-settings.component.scss'] }) export class TwoFactorAuthSettingsComponent extends PageComponent implements OnInit, HasConfirmForm, OnDestroy { @@ -73,7 +73,6 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI if (this.twoFaFormGroup.valid) { const setting = this.twoFaFormGroup.value as TwoFactorAuthSettingsForm; this.joinRateLimit(setting, 'verificationCodeCheckRateLimit'); - this.joinRateLimit(setting, 'verificationCodeSendRateLimit'); const providers = setting.providers.filter(provider => provider.enable); providers.forEach(provider => delete provider.enable); const config = Object.assign(setting, {providers}); @@ -91,18 +90,14 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI } } - toggleProviders($event: Event, i: number): void { - this.toggleExtensionPanel($event, i + 2, this.providersForm.at(i).get('enable').value); - } - - toggleExtensionPanel($event: Event, i: number, currentState: boolean) { + toggleExtensionPanel($event: Event, index: number, currentState: boolean) { if ($event) { $event.stopPropagation(); } if (currentState) { - this.getByIndexPanel(i).close(); + this.getByIndexPanel(index).close(); } else { - this.getByIndexPanel(i).open(); + this.getByIndexPanel(index).open(); } } @@ -130,9 +125,7 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI verificationCodeCheckRateLimitEnable: [false], verificationCodeCheckRateLimitNumber: ['3', [Validators.required, Validators.min(1), Validators.pattern(/^\d*$/)]], verificationCodeCheckRateLimitTime: ['900', [Validators.required, Validators.min(1), Validators.pattern(/^\d*$/)]], - verificationCodeSendRateLimitEnable: [false], - verificationCodeSendRateLimitNumber: ['1', [Validators.required, Validators.min(1), Validators.pattern(/^\d*$/)]], - verificationCodeSendRateLimitTime: ['60', [Validators.required, Validators.min(1), Validators.pattern(/^\d*$/)]], + minVerificationCodeSendPeriod: ['30', [Validators.required, Validators.min(5), Validators.pattern(/^\d*$/)]], providers: this.fb.array([]) }); Object.values(TwoFactorAuthProviderType).forEach(provider => { @@ -149,43 +142,25 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI this.twoFaFormGroup.get('verificationCodeCheckRateLimitTime').disable({emitEvent: false}); } }); - this.twoFaFormGroup.get('verificationCodeSendRateLimitEnable').valueChanges.pipe( - takeUntil(this.destroy$) - ).subscribe(value => { - if (value) { - this.twoFaFormGroup.get('verificationCodeSendRateLimitNumber').enable({emitEvent: false}); - this.twoFaFormGroup.get('verificationCodeSendRateLimitTime').enable({emitEvent: false}); - } else { - this.twoFaFormGroup.get('verificationCodeSendRateLimitNumber').disable({emitEvent: false}); - this.twoFaFormGroup.get('verificationCodeSendRateLimitTime').disable({emitEvent: false}); - } - }); } private setAuthConfigFormValue(settings: TwoFactorAuthSettings) { const [checkRateLimitNumber, checkRateLimitTime] = this.splitRateLimit(settings.verificationCodeCheckRateLimit); - const [sendRateLimitNumber, sendRateLimitTime] = this.splitRateLimit(settings.verificationCodeSendRateLimit); const allowProvidersConfig = settings.providers.map(provider => provider.providerType); const processFormValue: TwoFactorAuthSettingsForm = Object.assign(deepClone(settings), { verificationCodeCheckRateLimitEnable: checkRateLimitNumber > 0, verificationCodeCheckRateLimitNumber: checkRateLimitNumber || 3, verificationCodeCheckRateLimitTime: checkRateLimitTime || 900, - verificationCodeSendRateLimitEnable: sendRateLimitNumber > 0, - verificationCodeSendRateLimitNumber: sendRateLimitNumber || 1, - verificationCodeSendRateLimitTime: sendRateLimitTime || 60, providers: [] }); - if (sendRateLimitNumber > 0) { - this.getByIndexPanel(0).open(); - } if (checkRateLimitNumber > 0) { - this.getByIndexPanel(1).open(); + this.getByIndexPanel(3).open(); } Object.values(TwoFactorAuthProviderType).forEach((provider, index) => { const findIndex = allowProvidersConfig.indexOf(provider); if (findIndex > -1) { processFormValue.providers.push(Object.assign(settings.providers[findIndex], {enable: true})); - this.getByIndexPanel(index + 2).open(); + this.getByIndexPanel(index).open(); } else { processFormValue.providers.push({enable: false}); } @@ -203,9 +178,9 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI formControlConfig.issuerName = [{value: 'ThingsBoard', disabled: true}, Validators.required]; break; case TwoFactorAuthProviderType.SMS: - formControlConfig.smsVerificationMessageTemplate = [{value: 'Verification code: ${сode}', disabled: true}, [ + formControlConfig.smsVerificationMessageTemplate = [{value: 'Verification code: ${code}', disabled: true}, [ Validators.required, - Validators.pattern(/\${сode}/) + Validators.pattern(/\${code}/) ]]; formControlConfig.verificationCodeLifetime = [{value: 120, disabled: true}, [ Validators.required, diff --git a/ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html b/ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html index 8ebbe44b9d..78417564b3 100644 --- a/ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html +++ b/ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html @@ -46,20 +46,25 @@ inputmode="numeric" pattern="[0-9]*" autocomplete="off" placeholder="{{ 'security.2fa.dialog.verification-code' | translate }}"/> - + + {{ 'security.2fa.dialog.verification-code-invalid' | translate }} + + {{ 'login.resend-code-wait' | translate : {time: countDownTime} }} + + + {{ 'login.resend-code-wait' | translate : {time: countDownTime} }} + -
- -
- +