From bf11b90c43902ac150eef4e35dbc68a9f7f16273 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Fri, 12 Apr 2024 06:38:53 -0500 Subject: [PATCH] Use `UserVerificationDialogComponent` for account recovery enrollment (#8632) --- ...nroll-master-password-reset.component.html | 19 ---- .../enroll-master-password-reset.component.ts | 106 ++++++++---------- .../users/organization-user.module.ts | 14 --- apps/web/src/app/oss.module.ts | 2 - .../organization-options.component.ts | 13 ++- 5 files changed, 60 insertions(+), 94 deletions(-) delete mode 100644 apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.html delete mode 100644 apps/web/src/app/admin-console/organizations/users/organization-user.module.ts diff --git a/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.html b/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.html deleted file mode 100644 index 613e2a7a922..00000000000 --- a/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
- - {{ "enrollAccountRecovery" | i18n }} -
- - {{ "resetPasswordEnrollmentWarning" | i18n }} - - -
- - - - -
-
diff --git a/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.ts b/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.ts index 4cbdbf3864c..b228a4d135e 100644 --- a/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.ts +++ b/apps/web/src/app/admin-console/organizations/users/enroll-master-password-reset.component.ts @@ -1,12 +1,7 @@ -import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog"; -import { Component, Inject } from "@angular/core"; -import { FormControl, FormGroup, Validators } from "@angular/forms"; - +import { UserVerificationDialogComponent } from "@bitwarden/auth/angular"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { Verification } from "@bitwarden/common/auth/types/verification"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -19,63 +14,58 @@ interface EnrollMasterPasswordResetData { organization: Organization; } -@Component({ - selector: "app-enroll-master-password-reset", - templateUrl: "enroll-master-password-reset.component.html", -}) export class EnrollMasterPasswordReset { - protected organization: Organization; + constructor() {} - protected formGroup = new FormGroup({ - verification: new FormControl(null, Validators.required), - }); - - constructor( - private dialogRef: DialogRef, - @Inject(DIALOG_DATA) protected data: EnrollMasterPasswordResetData, - private resetPasswordService: OrganizationUserResetPasswordService, - private userVerificationService: UserVerificationService, - private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService, - private syncService: SyncService, - private logService: LogService, - private organizationUserService: OrganizationUserService, + static async open( + dialogService: DialogService, + data: EnrollMasterPasswordResetData, + resetPasswordService: OrganizationUserResetPasswordService, + organizationUserService: OrganizationUserService, + platformUtilsService: PlatformUtilsService, + i18nService: I18nService, + syncService: SyncService, + logService: LogService, ) { - this.organization = data.organization; - } + const result = await UserVerificationDialogComponent.open(dialogService, { + title: "enrollAccountRecovery", + calloutOptions: { + text: "resetPasswordEnrollmentWarning", + type: "warning", + }, + }); - submit = async () => { - try { - await this.userVerificationService - .buildRequest( - this.formGroup.value.verification, - OrganizationUserResetPasswordEnrollmentRequest, - ) - .then(async (request) => { - // Create request and execute enrollment - request.resetPasswordKey = await this.resetPasswordService.buildRecoveryKey( - this.organization.id, - ); - await this.organizationUserService.putOrganizationUserResetPasswordEnrollment( - this.organization.id, - this.organization.userId, - request, - ); - - await this.syncService.fullSync(true); - }); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("enrollPasswordResetSuccess"), - ); - this.dialogRef.close(); - } catch (e) { - this.logService.error(e); + // Handle the result of the dialog based on user action and verification success + if (result.userAction === "cancel") { + return; } - }; - static open(dialogService: DialogService, data: EnrollMasterPasswordResetData) { - return dialogService.open(EnrollMasterPasswordReset, { data }); + // User confirmed the dialog so check verification success + if (!result.verificationSuccess) { + // verification failed + return; + } + + // Verification succeeded + try { + // This object is missing most of the properties in the + // `OrganizationUserResetPasswordEnrollmentRequest()`, but those + // properties don't carry over to the server model anyway and are + // never used by this flow. + const request = new OrganizationUserResetPasswordEnrollmentRequest(); + request.resetPasswordKey = await resetPasswordService.buildRecoveryKey(data.organization.id); + + await organizationUserService.putOrganizationUserResetPasswordEnrollment( + data.organization.id, + data.organization.userId, + request, + ); + + platformUtilsService.showToast("success", null, i18nService.t("enrollPasswordResetSuccess")); + + await syncService.fullSync(true); + } catch (e) { + logService.error(e); + } } } diff --git a/apps/web/src/app/admin-console/organizations/users/organization-user.module.ts b/apps/web/src/app/admin-console/organizations/users/organization-user.module.ts deleted file mode 100644 index 30e2b5abe7b..00000000000 --- a/apps/web/src/app/admin-console/organizations/users/organization-user.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ScrollingModule } from "@angular/cdk/scrolling"; -import { NgModule } from "@angular/core"; - -import { UserVerificationModule } from "../../../auth/shared/components/user-verification"; -import { LooseComponentsModule, SharedModule } from "../../../shared"; - -import { EnrollMasterPasswordReset } from "./enroll-master-password-reset.component"; - -@NgModule({ - imports: [SharedModule, ScrollingModule, LooseComponentsModule, UserVerificationModule], - declarations: [EnrollMasterPasswordReset], - exports: [EnrollMasterPasswordReset], -}) -export class OrganizationUserModule {} diff --git a/apps/web/src/app/oss.module.ts b/apps/web/src/app/oss.module.ts index 73c03fd5dc8..3f18440d231 100644 --- a/apps/web/src/app/oss.module.ts +++ b/apps/web/src/app/oss.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; -import { OrganizationUserModule } from "./admin-console/organizations/users/organization-user.module"; import { AuthModule } from "./auth"; import { LoginModule } from "./auth/login/login.module"; import { TrialInitiationModule } from "./auth/trial-initiation/trial-initiation.module"; @@ -16,7 +15,6 @@ import { VaultFilterModule } from "./vault/individual-vault/vault-filter/vault-f TrialInitiationModule, VaultFilterModule, OrganizationBadgeModule, - OrganizationUserModule, LoginModule, AuthModule, AccessComponent, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts index fa81abdc54f..8dd63e62ddb 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts @@ -16,6 +16,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService } from "@bitwarden/components"; +import { OrganizationUserResetPasswordService } from "../../../../admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service"; import { EnrollMasterPasswordReset } from "../../../../admin-console/organizations/users/enroll-master-password-reset.component"; import { OptionsInput } from "../shared/components/vault-filter-section.component"; import { OrganizationFilter } from "../shared/models/vault-filter.type"; @@ -46,6 +47,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { private organizationUserService: OrganizationUserService, private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, private dialogService: DialogService, + private resetPasswordService: OrganizationUserResetPasswordService, ) {} async ngOnInit() { @@ -144,7 +146,16 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { async toggleResetPasswordEnrollment(org: Organization) { if (!this.organization.resetPasswordEnrolled) { - EnrollMasterPasswordReset.open(this.dialogService, { organization: org }); + await EnrollMasterPasswordReset.open( + this.dialogService, + { organization: org }, + this.resetPasswordService, + this.organizationUserService, + this.platformUtilsService, + this.i18nService, + this.syncService, + this.logService, + ); } else { // Remove reset password const request = new OrganizationUserResetPasswordEnrollmentRequest();