diff --git a/apps/web/src/app/components/user-verification/user-verification-prompt.component.html b/apps/web/src/app/components/user-verification/user-verification-prompt.component.html index de578f348b..4c73450e33 100644 --- a/apps/web/src/app/components/user-verification/user-verification-prompt.component.html +++ b/apps/web/src/app/components/user-verification/user-verification-prompt.component.html @@ -3,7 +3,10 @@ {{ modalTitle | i18n }}

{{ confirmDescription | i18n }}

- +
diff --git a/apps/web/src/app/components/user-verification/user-verification-prompt.component.ts b/apps/web/src/app/components/user-verification/user-verification-prompt.component.ts index 6d8ef945f6..eb8d3f5caf 100644 --- a/apps/web/src/app/components/user-verification/user-verification-prompt.component.ts +++ b/apps/web/src/app/components/user-verification/user-verification-prompt.component.ts @@ -8,7 +8,6 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; - import { DialogServiceAbstraction } from "../../../../../../libs/angular/src/services/dialog"; export interface UserVerificationPromptParams { diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 578caf9ad5..544f4cb3e7 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -2658,6 +2658,12 @@ "failedLogin2fa": { "message": "Login attempt failed with incorrect two-step login." }, + "incorrectPassword": { + "message": "Incorrect password" + }, + "incorrectCode": { + "message": "Incorrect code" + }, "exportedVault": { "message": "Vault exported" }, diff --git a/libs/angular/src/auth/components/user-verification-prompt.component.ts b/libs/angular/src/auth/components/user-verification-prompt.component.ts index 55f3e216d8..6aa06eb822 100644 --- a/libs/angular/src/auth/components/user-verification-prompt.component.ts +++ b/libs/angular/src/auth/components/user-verification-prompt.component.ts @@ -22,6 +22,8 @@ export class UserVerificationPromptComponent { secret: this.formBuilder.control(null), }); + protected invalidSecret = false; + constructor( private modalRef: ModalRef, protected config: ModalConfig, @@ -45,7 +47,9 @@ export class UserVerificationPromptComponent { try { //Incorrect secret will throw an invalid password error. await this.userVerificationService.verifyUser(this.secret.value); + this.invalidSecret = false; } catch (e) { + this.invalidSecret = true; this.platformUtilsService.showToast( "error", this.i18nService.t("error"), diff --git a/libs/angular/src/auth/components/user-verification.component.ts b/libs/angular/src/auth/components/user-verification.component.ts index 63ddd0e9bc..d8b46810a0 100644 --- a/libs/angular/src/auth/components/user-verification.component.ts +++ b/libs/angular/src/auth/components/user-verification.component.ts @@ -1,6 +1,7 @@ -import { Directive, OnInit } from "@angular/core"; +import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { ControlValueAccessor, FormControl, Validators } from "@angular/forms"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -18,17 +19,39 @@ import { Verification } from "@bitwarden/common/types/verification"; }) // eslint-disable-next-line rxjs-angular/prefer-takeuntil export class UserVerificationComponent implements ControlValueAccessor, OnInit { + private _invalidSecret = false; + @Input() + get invalidSecret() { + return this._invalidSecret; + } + set invalidSecret(value: boolean) { + this._invalidSecret = value; + this.invalidSecretChange.emit(value); + this.secret.updateValueAndValidity({ emitEvent: false }); + } + @Output() invalidSecretChange = new EventEmitter(); + usesKeyConnector = false; disableRequestOTP = false; sentCode = false; - secret = new FormControl("", [Validators.required]); + secret = new FormControl("", [ + Validators.required, + () => { + if (this.invalidSecret) { + return { + invalidSecret: { message: this.i18nService.t("incorrectPassword") }, + }; + } + }, + ]); private onChange: (value: Verification) => void; constructor( private keyConnectorService: KeyConnectorService, - private userVerificationService: UserVerificationService + private userVerificationService: UserVerificationService, + private i18nService: I18nService ) {} async ngOnInit() { @@ -72,7 +95,9 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit { } } - private processChanges(secret: string) { + protected processChanges(secret: string) { + this.invalidSecret = false; + if (this.onChange == null) { return; } diff --git a/libs/components/src/input/input.directive.ts b/libs/components/src/input/input.directive.ts index 2c4cb61eb2..60589208d5 100644 --- a/libs/components/src/input/input.directive.ts +++ b/libs/components/src/input/input.directive.ts @@ -78,15 +78,9 @@ export class BitInputDirective implements BitFormFieldControl { return this.id; } - private isActive = true; - @HostListener("blur") - onBlur() { - this.isActive = true; - } - @HostListener("input") onInput() { - this.isActive = false; + this.ngControl?.control?.markAsUntouched(); } get hasError() { @@ -97,7 +91,7 @@ export class BitInputDirective implements BitFormFieldControl { this.ngControl?.errors != null ); } else { - return this.ngControl?.status === "INVALID" && this.ngControl?.touched && this.isActive; + return this.ngControl?.status === "INVALID" && this.ngControl?.touched; } }