From eb7eb614f5c5c3982ce1f6ccfa8c6647e836f820 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:00:03 -0400 Subject: [PATCH] PM-11962 - InputPasswordComp - add weak password checking (#11252) --- .../input-password.component.ts | 102 ++++++++++++------ 1 file changed, 71 insertions(+), 31 deletions(-) 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 0aecb6e378..dbacf28054 100644 --- a/libs/auth/src/angular/input-password/input-password.component.ts +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -129,38 +129,13 @@ export class InputPasswordComponent { const password = this.formGroup.controls.password.value; - // Check if password is breached (if breached, user chooses to accept and continue or not) - const passwordIsBreached = - this.formGroup.controls.checkForBreaches.value && - (await this.auditService.passwordLeaked(password)); - - if (passwordIsBreached) { - const userAcceptedDialog = await this.dialogService.openSimpleDialog({ - title: { key: "exposedMasterPassword" }, - content: { key: "exposedMasterPasswordDesc" }, - type: "warning", - }); - - if (!userAcceptedDialog) { - return; - } - } - - // Check if password meets org policy requirements - if ( - this.masterPasswordPolicyOptions != null && - !this.policyService.evaluateMasterPassword( - this.passwordStrengthScore, - password, - this.masterPasswordPolicyOptions, - ) - ) { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("errorOccurred"), - message: this.i18nService.t("masterPasswordPolicyRequirementsNotMet"), - }); + const passwordEvaluatedSuccessfully = await this.evaluatePassword( + password, + this.passwordStrengthScore, + this.formGroup.controls.checkForBreaches.value, + ); + if (!passwordEvaluatedSuccessfully) { return; } @@ -194,4 +169,69 @@ export class InputPasswordComponent { password, }); }; + + // Returns true if the password passes all checks, false otherwise + private async evaluatePassword( + password: string, + passwordStrengthScore: PasswordStrengthScore, + checkForBreaches: boolean, + ) { + // Check if the password is breached, weak, or both + const passwordIsBreached = + checkForBreaches && (await this.auditService.passwordLeaked(password)); + + const passwordWeak = passwordStrengthScore != null && passwordStrengthScore < 3; + + if (passwordIsBreached && passwordWeak) { + const userAcceptedDialog = await this.dialogService.openSimpleDialog({ + title: { key: "weakAndExposedMasterPassword" }, + content: { key: "weakAndBreachedMasterPasswordDesc" }, + type: "warning", + }); + + if (!userAcceptedDialog) { + return false; + } + } else if (passwordWeak) { + const userAcceptedDialog = await this.dialogService.openSimpleDialog({ + title: { key: "weakMasterPasswordDesc" }, + content: { key: "weakMasterPasswordDesc" }, + type: "warning", + }); + + if (!userAcceptedDialog) { + return false; + } + } else if (passwordIsBreached) { + const userAcceptedDialog = await this.dialogService.openSimpleDialog({ + title: { key: "exposedMasterPassword" }, + content: { key: "exposedMasterPasswordDesc" }, + type: "warning", + }); + + if (!userAcceptedDialog) { + return false; + } + } + + // Check if password meets org policy requirements + if ( + this.masterPasswordPolicyOptions != null && + !this.policyService.evaluateMasterPassword( + this.passwordStrengthScore, + password, + this.masterPasswordPolicyOptions, + ) + ) { + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("masterPasswordPolicyRequirementsNotMet"), + }); + + return false; + } + + return true; + } }