From 4772362928475de4165d86b8b0d00cd73838c83c Mon Sep 17 00:00:00 2001 From: Alec Rippberger <127791530+alec-livefront@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:13:11 -0500 Subject: [PATCH] refactor(auth): [PM-8976] migrate two-factor setup component to Tailwind and standalone - Remove Bootstrap styles from two-factor-setup component and replace with Tailwind equivalents - Convert two factor components to standalone components to move away from LooseComponents - Replace ul/li list with bit-item-group and bit-item components - Integrate with the bit design system --------- Co-authored-by: Oscar Hinton Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> --- .../src/popup/images/two-factor/rc-w.png | Bin 3411 -> 0 bytes .../src/popup/images/two-factor/rc.png | Bin 3694 -> 0 bytes apps/browser/src/popup/scss/plugins.scss | 8 -- apps/desktop/src/images/two-factor/rc-w.png | Bin 3411 -> 0 bytes apps/desktop/src/images/two-factor/rc.png | Bin 3694 -> 0 bytes apps/desktop/src/scss/plugins.scss | 8 -- .../settings/organization-settings.module.ts | 3 + .../two-factor-recovery.component.ts | 40 +++++-- ...-factor-setup-authenticator.component.html | 2 +- ...wo-factor-setup-authenticator.component.ts | 30 ++++- .../two-factor-setup-duo.component.html | 4 +- .../two-factor-setup-duo.component.ts | 51 ++++++--- .../two-factor-setup-email.component.ts | 54 ++++++--- .../two-factor-setup-method-base.component.ts | 27 +++-- .../two-factor-setup-webauthn.component.html | 10 +- .../two-factor-setup-webauthn.component.ts | 76 +++++++++---- .../two-factor-setup-yubikey.component.html | 10 +- .../two-factor-setup-yubikey.component.ts | 106 ++++++++++++++---- .../two-factor-setup.component.html | 32 +++--- .../two-factor/two-factor-setup.component.ts | 7 +- .../two-factor/two-factor-verify.component.ts | 61 +++++++--- .../src/app/shared/loose-components.module.ts | 23 ---- apps/web/src/images/two-factor/rc-w.png | Bin 3411 -> 0 bytes apps/web/src/images/two-factor/rc.png | Bin 3694 -> 0 bytes apps/web/src/scss/plugins.scss | 14 --- .../src/menu/menu.component.spec.ts | 2 +- 26 files changed, 374 insertions(+), 194 deletions(-) delete mode 100644 apps/browser/src/popup/images/two-factor/rc-w.png delete mode 100644 apps/browser/src/popup/images/two-factor/rc.png delete mode 100644 apps/desktop/src/images/two-factor/rc-w.png delete mode 100644 apps/desktop/src/images/two-factor/rc.png delete mode 100644 apps/web/src/images/two-factor/rc-w.png delete mode 100644 apps/web/src/images/two-factor/rc.png diff --git a/apps/browser/src/popup/images/two-factor/rc-w.png b/apps/browser/src/popup/images/two-factor/rc-w.png deleted file mode 100644 index e83b8db13243687a7eb44e9c676f6c45ed54dc35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3411 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 Nt;}uAYE3-}{|88xeg*&l diff --git a/apps/browser/src/popup/images/two-factor/rc.png b/apps/browser/src/popup/images/two-factor/rc.png deleted file mode 100644 index 4bebdf936ccfa8409d6bc74f7bc1a5ac4ec269f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3694 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 Zm{ExN^XE!`#BhEW%uk&m6yjW?{tNL&o*e)H diff --git a/apps/browser/src/popup/scss/plugins.scss b/apps/browser/src/popup/scss/plugins.scss index b8ac8697b7..591e8a1bd0 100644 --- a/apps/browser/src/popup/scss/plugins.scss +++ b/apps/browser/src/popup/scss/plugins.scss @@ -21,11 +21,3 @@ max-width: 100px; } } - -.recovery-code-img { - @include themify($themes) { - content: url("../images/two-factor/rc" + themed("mfaLogoSuffix")); - max-width: 100px; - max-height: 45px; - } -} diff --git a/apps/desktop/src/images/two-factor/rc-w.png b/apps/desktop/src/images/two-factor/rc-w.png deleted file mode 100644 index e83b8db13243687a7eb44e9c676f6c45ed54dc35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3411 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 Nt;}uAYE3-}{|88xeg*&l diff --git a/apps/desktop/src/images/two-factor/rc.png b/apps/desktop/src/images/two-factor/rc.png deleted file mode 100644 index 4bebdf936ccfa8409d6bc74f7bc1a5ac4ec269f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3694 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 Zm{ExN^XE!`#BhEW%uk&m6yjW?{tNL&o*e)H diff --git a/apps/desktop/src/scss/plugins.scss b/apps/desktop/src/scss/plugins.scss index b8ac8697b7..591e8a1bd0 100644 --- a/apps/desktop/src/scss/plugins.scss +++ b/apps/desktop/src/scss/plugins.scss @@ -21,11 +21,3 @@ max-width: 100px; } } - -.recovery-code-img { - @include themify($themes) { - content: url("../images/two-factor/rc" + themed("mfaLogoSuffix")); - max-width: 100px; - max-height: 45px; - } -} diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts index 2a2068d581..bfff3b2aa2 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts @@ -1,5 +1,7 @@ import { NgModule } from "@angular/core"; +import { ItemModule } from "@bitwarden/components"; + import { LooseComponentsModule, SharedModule } from "../../../shared"; import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component"; import { PoliciesModule } from "../../organizations/policies"; @@ -15,6 +17,7 @@ import { TwoFactorSetupComponent } from "./two-factor-setup.component"; PoliciesModule, OrganizationSettingsRoutingModule, AccountFingerprintComponent, + ItemModule, ], declarations: [AccountComponent, TwoFactorSetupComponent], }) diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-recovery.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-recovery.component.ts index 19e01af4b0..75a9766131 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-recovery.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-recovery.component.ts @@ -1,36 +1,50 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore +import { CommonModule } from "@angular/common"; import { Component, Inject } from "@angular/core"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorRecoverResponse } from "@bitwarden/common/auth/models/response/two-factor-recover.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { DIALOG_DATA, DialogConfig, DialogService } from "@bitwarden/components"; +import { + ButtonModule, + DIALOG_DATA, + DialogConfig, + DialogModule, + DialogRef, + DialogService, + TypographyModule, +} from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; @Component({ selector: "app-two-factor-recovery", templateUrl: "two-factor-recovery.component.html", + standalone: true, + imports: [CommonModule, DialogModule, ButtonModule, TypographyModule, I18nPipe], }) export class TwoFactorRecoveryComponent { type = -1; - code: string; - authed: boolean; + code: string = ""; + authed: boolean = false; twoFactorProviderType = TwoFactorProviderType; constructor( - @Inject(DIALOG_DATA) protected data: any, + @Inject(DIALOG_DATA) protected data: { response: { response: TwoFactorRecoverResponse } }, private i18nService: I18nService, ) { this.auth(data.response); } - auth(authResponse: any) { + auth(authResponse: { response: TwoFactorRecoverResponse }) { this.authed = true; this.processResponse(authResponse.response); } print() { const w = window.open(); + if (!w) { + // return early if the window is not open + return; + } w.document.write( '
' + "

" + @@ -47,9 +61,9 @@ export class TwoFactorRecoveryComponent { w.print(); } - private formatString(s: string) { + private formatString(s: string): string { if (s == null) { - return null; + return ""; } return s .replace(/(.{4})/g, "$1 ") @@ -61,7 +75,13 @@ export class TwoFactorRecoveryComponent { this.code = this.formatString(response.code); } - static open(dialogService: DialogService, config: DialogConfig) { + static open( + dialogService: DialogService, + config: DialogConfig< + { response: { response: TwoFactorRecoverResponse } }, + DialogRef + >, + ) { return dialogService.open(TwoFactorRecoveryComponent, config); } } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.html index a31d4c3345..1595c0350d 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.html @@ -41,7 +41,7 @@ {{ "twoStepAuthenticatorInstructionSuffix" | i18n }}

-

+

- + {{ "twoStepLoginProviderEnabled" | i18n }} - + Duo logo {{ "twoFactorDuoClientId" | i18n }}: {{ clientId }}
diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts index 833ce5c1cb..bada3301a9 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts @@ -1,7 +1,6 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore +import { CommonModule } from "@angular/common"; import { Component, EventEmitter, Inject, OnInit, Output } from "@angular/core"; -import { FormBuilder, Validators } from "@angular/forms"; +import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -13,18 +12,41 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { + AsyncActionsModule, + ButtonModule, + CalloutModule, DIALOG_DATA, DialogConfig, + DialogModule, DialogRef, DialogService, + FormFieldModule, + IconModule, + InputModule, ToastService, + TypographyModule, } from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; import { TwoFactorSetupMethodBaseComponent } from "./two-factor-setup-method-base.component"; @Component({ selector: "app-two-factor-setup-duo", templateUrl: "two-factor-setup-duo.component.html", + standalone: true, + imports: [ + CommonModule, + DialogModule, + FormFieldModule, + InputModule, + TypographyModule, + ButtonModule, + IconModule, + I18nPipe, + ReactiveFormsModule, + AsyncActionsModule, + CalloutModule, + ], }) export class TwoFactorSetupDuoComponent extends TwoFactorSetupMethodBaseComponent @@ -63,23 +85,23 @@ export class TwoFactorSetupDuoComponent ); } - get clientId() { - return this.formGroup.get("clientId").value; + get clientId(): string { + return this.formGroup.get("clientId")?.value || ""; } - get clientSecret() { - return this.formGroup.get("clientSecret").value; + get clientSecret(): string { + return this.formGroup.get("clientSecret")?.value || ""; } - get host() { - return this.formGroup.get("host").value; + get host(): string { + return this.formGroup.get("host")?.value || ""; } set clientId(value: string) { - this.formGroup.get("clientId").setValue(value); + this.formGroup.get("clientId")?.setValue(value); } set clientSecret(value: string) { - this.formGroup.get("clientSecret").setValue(value); + this.formGroup.get("clientSecret")?.setValue(value); } set host(value: string) { - this.formGroup.get("host").setValue(value); + this.formGroup.get("host")?.setValue(value); } async ngOnInit() { @@ -147,7 +169,10 @@ export class TwoFactorSetupDuoComponent dialogService: DialogService, config: DialogConfig, ) => { - return dialogService.open(TwoFactorSetupDuoComponent, config); + return dialogService.open( + TwoFactorSetupDuoComponent, + config as DialogConfig>, + ); }; } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts index 40f50a3393..c5692c3f08 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts @@ -1,7 +1,6 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore +import { CommonModule } from "@angular/common"; import { Component, EventEmitter, Inject, OnInit, Output } from "@angular/core"; -import { FormBuilder, Validators } from "@angular/forms"; +import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -16,19 +15,41 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { + AsyncActionsModule, + ButtonModule, + CalloutModule, DIALOG_DATA, DialogConfig, + DialogModule, DialogRef, DialogService, + FormFieldModule, + IconModule, + InputModule, ToastService, + TypographyModule, } from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; import { TwoFactorSetupMethodBaseComponent } from "./two-factor-setup-method-base.component"; @Component({ selector: "app-two-factor-setup-email", templateUrl: "two-factor-setup-email.component.html", - outputs: ["onUpdated"], + standalone: true, + imports: [ + AsyncActionsModule, + ButtonModule, + CalloutModule, + CommonModule, + DialogModule, + FormFieldModule, + IconModule, + I18nPipe, + InputModule, + ReactiveFormsModule, + TypographyModule, + ], }) export class TwoFactorSetupEmailComponent extends TwoFactorSetupMethodBaseComponent @@ -36,8 +57,8 @@ export class TwoFactorSetupEmailComponent { @Output() onChangeStatus: EventEmitter = new EventEmitter(); type = TwoFactorProviderType.Email; - sentEmail: string; - emailPromise: Promise; + sentEmail: string = ""; + emailPromise: Promise | undefined; override componentName = "app-two-factor-email"; formGroup = this.formBuilder.group({ token: ["", [Validators.required]], @@ -67,17 +88,17 @@ export class TwoFactorSetupEmailComponent toastService, ); } - get token() { - return this.formGroup.get("token").value; + get token(): string { + return this.formGroup.get("token")?.value || ""; } - set token(value: string) { - this.formGroup.get("token").setValue(value); + set token(value: string | null) { + this.formGroup.get("token")?.setValue(value || ""); } - get email() { - return this.formGroup.get("email").value; + get email(): string { + return this.formGroup.get("email")?.value || ""; } - set email(value: string) { - this.formGroup.get("email").setValue(value); + set email(value: string | null | undefined) { + this.formGroup.get("email")?.setValue(value || ""); } async ngOnInit() { @@ -149,6 +170,9 @@ export class TwoFactorSetupEmailComponent dialogService: DialogService, config: DialogConfig>, ) { - return dialogService.open(TwoFactorSetupEmailComponent, config); + return dialogService.open>( + TwoFactorSetupEmailComponent, + config as DialogConfig, DialogRef>, + ); } } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts index b87b92a965..0654ad126e 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Directive, EventEmitter, Output } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -17,18 +15,20 @@ import { DialogService, ToastService } from "@bitwarden/components"; /** * Base class for two-factor setup components (ex: email, yubikey, webauthn, duo). */ -@Directive() +@Directive({ + standalone: true, +}) export abstract class TwoFactorSetupMethodBaseComponent { @Output() onUpdated = new EventEmitter(); - type: TwoFactorProviderType; - organizationId: string; + type: TwoFactorProviderType | undefined; + organizationId: string | null = null; twoFactorProviderType = TwoFactorProviderType; enabled = false; authed = false; - protected hashedSecret: string; - protected verificationType: VerificationType; + protected hashedSecret: string | undefined; + protected verificationType: VerificationType | undefined; protected componentName = ""; constructor( @@ -74,6 +74,9 @@ export abstract class TwoFactorSetupMethodBaseComponent { try { const request = await this.buildRequestModel(TwoFactorProviderRequest); + if (this.type === undefined) { + throw new Error("Two-factor provider type is required"); + } request.type = this.type; if (this.organizationId != null) { promise = this.apiService.putTwoFactorOrganizationDisable(this.organizationId, request); @@ -84,7 +87,7 @@ export abstract class TwoFactorSetupMethodBaseComponent { this.enabled = false; this.toastService.showToast({ variant: "success", - title: null, + title: "", message: this.i18nService.t("twoStepDisabled"), }); this.onUpdated.emit(false); @@ -105,6 +108,9 @@ export abstract class TwoFactorSetupMethodBaseComponent { } const request = await this.buildRequestModel(TwoFactorProviderRequest); + if (this.type === undefined) { + throw new Error("Two-factor provider type is required"); + } request.type = this.type; if (this.organizationId != null) { await this.apiService.putTwoFactorOrganizationDisable(this.organizationId, request); @@ -114,7 +120,7 @@ export abstract class TwoFactorSetupMethodBaseComponent { this.enabled = false; this.toastService.showToast({ variant: "success", - title: null, + title: "", message: this.i18nService.t("twoStepDisabled"), }); this.onUpdated.emit(false); @@ -123,6 +129,9 @@ export abstract class TwoFactorSetupMethodBaseComponent { protected async buildRequestModel( requestClass: new () => T, ) { + if (this.hashedSecret === undefined || this.verificationType === undefined) { + throw new Error("User verification data is missing"); + } return this.userVerificationService.buildRequest( { secret: this.hashedSecret, diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html index 4d50516163..767934cf3d 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.html @@ -5,23 +5,23 @@ [subtitle]="'webAuthnTitle' | i18n" > - {{ "twoStepLoginProviderEnabled" | i18n }} - - + +

{{ "twoFactorWebAuthnWarning1" | i18n }}

- + FIDO2 WebAuthn logo