1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-24 08:33:29 +00:00
Files
browser/apps/web/src/app/auth/settings/account/account.component.ts
Dave cf6569bfea feat(user-decryption-options) [PM-26413]: Remove ActiveUserState from UserDecryptionOptionsService (#16894)
* feat(user-decryption-options) [PM-26413]: Update UserDecryptionOptionsService and tests to use UserId-only APIs.

* feat(user-decryption-options) [PM-26413]: Update InternalUserDecryptionOptionsService call sites to use UserId-only API.

* feat(user-decryption-options) [PM-26413] Update userDecryptionOptions$ call sites to use the UserId-only API.

* feat(user-decryption-options) [PM-26413]: Update additional call sites.

* feat(user-decryption-options) [PM-26413]: Update dependencies and an additional call site.

* feat(user-verification-service) [PM-26413]: Replace where allowed by unrestricted imports invocation of UserVerificationService.hasMasterPassword (deprecated) with UserDecryptionOptions.hasMasterPasswordById$. Additional work to complete as tech debt tracked in PM-27009.

* feat(user-decryption-options) [PM-26413]: Update for non-null strict adherence.

* feat(user-decryption-options) [PM-26413]: Update type safety and defensive returns.

* chore(user-decryption-options) [PM-26413]: Comment cleanup.

* feat(user-decryption-options) [PM-26413]: Update tests.

* feat(user-decryption-options) [PM-26413]: Standardize null-checking on active account id for new API consumption.

* feat(vault-timeout-settings-service) [PM-26413]: Add test cases to illustrate null active account from AccountService.

* fix(fido2-user-verification-service-spec) [PM-26413]: Update test harness to use FakeAccountService.

* fix(downstream-components) [PM-26413]: Prefer use of the getUserId operator in all authenticated contexts for user id provided to UserDecryptionOptionsService.

---------

Co-authored-by: bnagawiecki <107435978+bnagawiecki@users.noreply.github.com>
2025-11-25 11:23:22 -05:00

101 lines
3.8 KiB
TypeScript

import { Component, OnInit, OnDestroy } from "@angular/core";
import { firstValueFrom, lastValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { DialogService } from "@bitwarden/components";
import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared";
import { PurgeVaultComponent } from "../../../vault/settings/purge-vault.component";
import { ChangeEmailComponent } from "./change-email.component";
import { DangerZoneComponent } from "./danger-zone.component";
import { DeauthorizeSessionsComponent } from "./deauthorize-sessions.component";
import { DeleteAccountDialogComponent } from "./delete-account-dialog.component";
import { ProfileComponent } from "./profile.component";
import { SetAccountVerifyDevicesDialogComponent } from "./set-account-verify-devices-dialog.component";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
templateUrl: "account.component.html",
imports: [
SharedModule,
HeaderModule,
ProfileComponent,
ChangeEmailComponent,
DangerZoneComponent,
],
})
export class AccountComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
showChangeEmail$: Observable<boolean> = new Observable();
showPurgeVault$: Observable<boolean> = new Observable();
showDeleteAccount$: Observable<boolean> = new Observable();
verifyNewDeviceLogin: boolean = true;
constructor(
private accountService: AccountService,
private dialogService: DialogService,
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
private organizationService: OrganizationService,
) {}
async ngOnInit() {
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
const userIsManagedByOrganization$ = this.organizationService
.organizations$(userId)
.pipe(
map((organizations) => organizations.some((o) => o.userIsManagedByOrganization === true)),
);
const hasMasterPassword$ = this.userDecryptionOptionsService.hasMasterPasswordById$(userId);
this.showChangeEmail$ = hasMasterPassword$;
this.showPurgeVault$ = userIsManagedByOrganization$.pipe(
map((userIsManagedByOrganization) => !userIsManagedByOrganization),
);
this.showDeleteAccount$ = userIsManagedByOrganization$.pipe(
map((userIsManagedByOrganization) => !userIsManagedByOrganization),
);
this.accountService.accountVerifyNewDeviceLogin$
.pipe(takeUntil(this.destroy$))
.subscribe((verifyDevices) => {
this.verifyNewDeviceLogin = verifyDevices;
});
}
deauthorizeSessions = async () => {
const dialogRef = DeauthorizeSessionsComponent.open(this.dialogService);
await lastValueFrom(dialogRef.closed);
};
purgeVault = async () => {
const dialogRef = PurgeVaultComponent.open(this.dialogService);
await lastValueFrom(dialogRef.closed);
};
deleteAccount = async () => {
const dialogRef = DeleteAccountDialogComponent.open(this.dialogService);
await lastValueFrom(dialogRef.closed);
};
setNewDeviceLoginProtection = async () => {
const dialogRef = SetAccountVerifyDevicesDialogComponent.open(this.dialogService);
await lastValueFrom(dialogRef.closed);
};
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}