diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts index c935d0319bf..87bf612b8cd 100644 --- a/libs/auth/src/angular/input-password/input-password.component.ts +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -13,6 +13,7 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { HashPurpose } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { UserId } from "@bitwarden/common/types/guid"; @@ -193,6 +194,7 @@ export class InputPasswordComponent implements OnInit { private platformUtilsService: PlatformUtilsService, private policyService: PolicyService, private toastService: ToastService, + private validationService: ValidationService, ) {} ngOnInit(): void { @@ -263,136 +265,138 @@ export class InputPasswordComponent implements OnInit { } submit = async () => { - this.submittingBehaviorSubject.next(true); + try { + this.submittingBehaviorSubject.next(true); - this.verifyFlow(); + this.verifyFlow(); - this.formGroup.markAllAsTouched(); + this.formGroup.markAllAsTouched(); - if (this.formGroup.invalid) { - this.showErrorSummary = true; - this.submittingBehaviorSubject.next(false); - return; - } - - const currentPassword = this.formGroup.controls.currentPassword?.value ?? ""; - const newPassword = this.formGroup.controls.newPassword.value; - const newPasswordHint = this.formGroup.controls.newPasswordHint?.value ?? ""; - const checkForBreaches = this.formGroup.controls.checkForBreaches?.value ?? true; - - if (this.flow === InputPasswordFlow.ChangePasswordDelegation) { - await this.handleChangePasswordDelegationFlow(newPassword); - this.submittingBehaviorSubject.next(false); - return; - } - - if (!this.email) { - throw new Error("Email is required to create master key."); - } - - // 1. Determine kdfConfig - if (this.flow === InputPasswordFlow.SetInitialPasswordAccountRegistration) { - this.kdfConfig = DEFAULT_KDF_CONFIG; - } else { - if (!this.userId) { - throw new Error("userId not passed down"); - } - this.kdfConfig = await firstValueFrom(this.kdfConfigService.getKdfConfig$(this.userId)); - } - - if (this.kdfConfig == null) { - throw new Error("KdfConfig is required to create master key."); - } - - // 2. Verify current password is correct (if necessary) - if ( - this.flow === InputPasswordFlow.ChangePassword || - this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation - ) { - const currentPasswordVerified = await this.verifyCurrentPassword( - currentPassword, - this.kdfConfig, - ); - if (!currentPasswordVerified) { + if (this.formGroup.invalid) { + this.showErrorSummary = true; this.submittingBehaviorSubject.next(false); return; } - } - // 3. Verify new password - const newPasswordVerified = await this.verifyNewPassword( - newPassword, - this.passwordStrengthScore, - checkForBreaches, - ); - if (!newPasswordVerified) { - this.submittingBehaviorSubject.next(false); - return; - } + const currentPassword = this.formGroup.controls.currentPassword?.value ?? ""; + const newPassword = this.formGroup.controls.newPassword.value; + const newPasswordHint = this.formGroup.controls.newPasswordHint?.value ?? ""; + const checkForBreaches = this.formGroup.controls.checkForBreaches?.value ?? true; - // 4. Create cryptographic keys and build a PasswordInputResult object - const newMasterKey = await this.keyService.makeMasterKey( - newPassword, - this.email, - this.kdfConfig, - ); + if (this.flow === InputPasswordFlow.ChangePasswordDelegation) { + await this.handleChangePasswordDelegationFlow(newPassword); + return; + } - const newServerMasterKeyHash = await this.keyService.hashMasterKey( - newPassword, - newMasterKey, - HashPurpose.ServerAuthorization, - ); + if (!this.email) { + throw new Error("Email is required to create master key."); + } - const newLocalMasterKeyHash = await this.keyService.hashMasterKey( - newPassword, - newMasterKey, - HashPurpose.LocalAuthorization, - ); + // 1. Determine kdfConfig + if (this.flow === InputPasswordFlow.SetInitialPasswordAccountRegistration) { + this.kdfConfig = DEFAULT_KDF_CONFIG; + } else { + if (!this.userId) { + throw new Error("userId not passed down"); + } + this.kdfConfig = await firstValueFrom(this.kdfConfigService.getKdfConfig$(this.userId)); + } - const passwordInputResult: PasswordInputResult = { - newPassword, - newMasterKey, - newServerMasterKeyHash, - newLocalMasterKeyHash, - newPasswordHint, - kdfConfig: this.kdfConfig, - }; + if (this.kdfConfig == null) { + throw new Error("KdfConfig is required to create master key."); + } - if ( - this.flow === InputPasswordFlow.ChangePassword || - this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation - ) { - const currentMasterKey = await this.keyService.makeMasterKey( - currentPassword, + // 2. Verify current password is correct (if necessary) + if ( + this.flow === InputPasswordFlow.ChangePassword || + this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation + ) { + const currentPasswordVerified = await this.verifyCurrentPassword( + currentPassword, + this.kdfConfig, + ); + if (!currentPasswordVerified) { + return; + } + } + + // 3. Verify new password + const newPasswordVerified = await this.verifyNewPassword( + newPassword, + this.passwordStrengthScore, + checkForBreaches, + ); + if (!newPasswordVerified) { + return; + } + + // 4. Create cryptographic keys and build a PasswordInputResult object + const newMasterKey = await this.keyService.makeMasterKey( + newPassword, this.email, this.kdfConfig, ); - const currentServerMasterKeyHash = await this.keyService.hashMasterKey( - currentPassword, - currentMasterKey, + const newServerMasterKeyHash = await this.keyService.hashMasterKey( + newPassword, + newMasterKey, HashPurpose.ServerAuthorization, ); - const currentLocalMasterKeyHash = await this.keyService.hashMasterKey( - currentPassword, - currentMasterKey, + const newLocalMasterKeyHash = await this.keyService.hashMasterKey( + newPassword, + newMasterKey, HashPurpose.LocalAuthorization, ); - passwordInputResult.currentPassword = currentPassword; - passwordInputResult.currentMasterKey = currentMasterKey; - passwordInputResult.currentServerMasterKeyHash = currentServerMasterKeyHash; - passwordInputResult.currentLocalMasterKeyHash = currentLocalMasterKeyHash; - } + const passwordInputResult: PasswordInputResult = { + newPassword, + newMasterKey, + newServerMasterKeyHash, + newLocalMasterKeyHash, + newPasswordHint, + kdfConfig: this.kdfConfig, + }; - if (this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation) { - passwordInputResult.rotateUserKey = this.formGroup.controls.rotateUserKey?.value; - } + if ( + this.flow === InputPasswordFlow.ChangePassword || + this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation + ) { + const currentMasterKey = await this.keyService.makeMasterKey( + currentPassword, + this.email, + this.kdfConfig, + ); - // 5. Emit cryptographic keys and other password related properties - this.onPasswordFormSubmit.emit(passwordInputResult); - this.submittingBehaviorSubject.next(false); + const currentServerMasterKeyHash = await this.keyService.hashMasterKey( + currentPassword, + currentMasterKey, + HashPurpose.ServerAuthorization, + ); + + const currentLocalMasterKeyHash = await this.keyService.hashMasterKey( + currentPassword, + currentMasterKey, + HashPurpose.LocalAuthorization, + ); + + passwordInputResult.currentPassword = currentPassword; + passwordInputResult.currentMasterKey = currentMasterKey; + passwordInputResult.currentServerMasterKeyHash = currentServerMasterKeyHash; + passwordInputResult.currentLocalMasterKeyHash = currentLocalMasterKeyHash; + } + + if (this.flow === InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation) { + passwordInputResult.rotateUserKey = this.formGroup.controls.rotateUserKey?.value; + } + + // 5. Emit cryptographic keys and other password related properties + this.onPasswordFormSubmit.emit(passwordInputResult); + } catch (e) { + this.validationService.showError(e); + } finally { + this.submittingBehaviorSubject.next(false); + } }; /**