mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 23:33:31 +00:00
Merge branch 'main' into feature/passkey-provider
This commit is contained in:
@@ -4,3 +4,7 @@
|
||||
|
||||
export { LockComponent } from "./lock/components/lock.component";
|
||||
export { LockComponentService, UnlockOptions } from "./lock/services/lock-component.service";
|
||||
export { KeyRotationTrustInfoComponent } from "./key-rotation/key-rotation-trust-info.component";
|
||||
export { AccountRecoveryTrustComponent } from "./trust/account-recovery-trust.component";
|
||||
export { EmergencyAccessTrustComponent } from "./trust/emergency-access-trust.component";
|
||||
export { RemovePasswordComponent } from "./key-connector/remove-password.component";
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
@Directive()
|
||||
export class RemovePasswordComponent implements OnInit {
|
||||
actionPromise: Promise<void | boolean>;
|
||||
continuing = false;
|
||||
leaving = false;
|
||||
|
||||
loading = true;
|
||||
organization: Organization;
|
||||
email: string;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private syncService: SyncService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private dialogService: DialogService,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.organization = await this.keyConnectorService.getManagingOrganization();
|
||||
this.email = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.email)),
|
||||
);
|
||||
await this.syncService.fullSync(false);
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
convert = async () => {
|
||||
this.continuing = true;
|
||||
this.actionPromise = this.keyConnectorService.migrateUser();
|
||||
|
||||
try {
|
||||
await this.actionPromise;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("removedMasterPassword"),
|
||||
});
|
||||
await this.keyConnectorService.removeConvertAccountRequired();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate([""]);
|
||||
} catch (e) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: e.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
leave = async () => {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: this.organization.name,
|
||||
content: { key: "leaveOrganizationConfirmation" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.leaving = true;
|
||||
this.actionPromise = this.organizationApiService.leave(this.organization.id);
|
||||
await this.actionPromise;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("leftOrganization"),
|
||||
});
|
||||
await this.keyConnectorService.removeConvertAccountRequired();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate([""]);
|
||||
} catch (e) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: e,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<bit-dialog dialogSize="large">
|
||||
<span bitDialogTitle>
|
||||
<strong> {{ "userkeyRotationDisclaimerTitle" | i18n }} </strong>
|
||||
</span>
|
||||
<span bitDialogContent>
|
||||
{{ "userkeyRotationDisclaimerDescription" | i18n }}
|
||||
<ul class="tw-mt-2 tw-mb-0 tw-pl-4">
|
||||
<li *ngIf="params.orgName != null">
|
||||
{{ "userkeyRotationDisclaimerAccountRecoveryOrgsText" | i18n: params.orgName }}
|
||||
</li>
|
||||
<li *ngIf="params.numberOfEmergencyAccessUsers > 0">
|
||||
{{
|
||||
"userkeyRotationDisclaimerEmergencyAccessText" | i18n: params.numberOfEmergencyAccessUsers
|
||||
}}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<ng-container bitDialogFooter>
|
||||
<a bitButton target="_blank" rel="noreferrer" buttonType="primary" (click)="submit()">
|
||||
{{ "continue" | i18n }}
|
||||
</a>
|
||||
<button bitButton type="button" buttonType="secondary" bitDialogClose>
|
||||
{{ "close" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
@@ -0,0 +1,58 @@
|
||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
DialogService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
type KeyRotationTrustDialogData = {
|
||||
orgName?: string;
|
||||
numberOfEmergencyAccessUsers: number;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "key-rotation-trust-info",
|
||||
templateUrl: "key-rotation-trust-info.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
DialogModule,
|
||||
ButtonModule,
|
||||
ReactiveFormsModule,
|
||||
AsyncActionsModule,
|
||||
FormsModule,
|
||||
],
|
||||
})
|
||||
export class KeyRotationTrustInfoComponent {
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected params: KeyRotationTrustDialogData,
|
||||
private logService: LogService,
|
||||
private dialogRef: DialogRef<boolean>,
|
||||
) {}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
this.dialogRef.close(true);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Strongly typed helper to open a KeyRotationTrustComponent
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param data The data to pass to the dialog
|
||||
*/
|
||||
static open(dialogService: DialogService, data: KeyRotationTrustDialogData) {
|
||||
return dialogService.open<boolean, KeyRotationTrustDialogData>(KeyRotationTrustInfoComponent, {
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<ng-template #loading>
|
||||
<div class="tw-flex tw-items-center tw-justify-center" *ngIf="loading">
|
||||
<ng-template #spinner>
|
||||
<div class="tw-flex tw-items-center tw-justify-center">
|
||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" aria-hidden="true"></i>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-container *ngIf="unlockOptions; else loading">
|
||||
<ng-container *ngIf="unlockOptions && !loading; else spinner">
|
||||
<!-- Biometrics Unlock -->
|
||||
<ng-container *ngIf="activeUnlockOption === UnlockOption.Biometrics">
|
||||
<button
|
||||
|
||||
@@ -4,6 +4,7 @@ import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from "@angula
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import {
|
||||
BehaviorSubject,
|
||||
filter,
|
||||
firstValueFrom,
|
||||
interval,
|
||||
mergeMap,
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
switchMap,
|
||||
take,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
@@ -22,6 +24,7 @@ import { Account, AccountService } from "@bitwarden/common/auth/abstractions/acc
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import {
|
||||
MasterPasswordVerification,
|
||||
MasterPasswordVerificationResponse,
|
||||
@@ -87,6 +90,7 @@ const AUTOPROMPT_BIOMETRICS_PROCESS_RELOAD_DELAY = 5000;
|
||||
})
|
||||
export class LockComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
protected loading = true;
|
||||
|
||||
activeAccount: Account | null = null;
|
||||
|
||||
@@ -121,6 +125,9 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
|
||||
formGroup: FormGroup | null = null;
|
||||
|
||||
// Browser extension properties:
|
||||
private shouldClosePopout = false;
|
||||
|
||||
// Desktop properties:
|
||||
private deferFocus: boolean | null = null;
|
||||
private biometricAsked = false;
|
||||
@@ -228,22 +235,22 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
private listenForActiveAccountChanges() {
|
||||
this.accountService.activeAccount$
|
||||
.pipe(
|
||||
switchMap((account) => {
|
||||
return this.handleActiveAccountChange(account);
|
||||
tap((account) => {
|
||||
this.loading = true;
|
||||
this.activeAccount = account;
|
||||
this.resetDataOnActiveAccountChange();
|
||||
}),
|
||||
filter((account): account is Account => account != null),
|
||||
switchMap(async (account) => {
|
||||
await this.handleActiveAccountChange(account);
|
||||
this.loading = false;
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private async handleActiveAccountChange(activeAccount: Account | null) {
|
||||
this.activeAccount = activeAccount;
|
||||
|
||||
this.resetDataOnActiveAccountChange();
|
||||
|
||||
if (activeAccount == null) {
|
||||
return;
|
||||
}
|
||||
private async handleActiveAccountChange(activeAccount: Account) {
|
||||
// this account may be unlocked, prevent any prompts so we can redirect to vault
|
||||
if (await this.keyService.hasUserKeyInMemory(activeAccount.id)) {
|
||||
return;
|
||||
@@ -300,16 +307,12 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
// desktop and extension.
|
||||
if (this.clientType === "desktop") {
|
||||
if (autoPromptBiometrics) {
|
||||
this.loading = false;
|
||||
await this.desktopAutoPromptBiometrics();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.clientType === "browser") {
|
||||
// Firefox closes the popup when unfocused, so this would block all unlock methods
|
||||
if (this.platformUtilsService.getDevice() === DeviceType.FirefoxExtension) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.unlockOptions?.biometrics.enabled &&
|
||||
autoPromptBiometrics &&
|
||||
@@ -323,6 +326,12 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
isNaN(lastProcessReload.getTime()) ||
|
||||
Date.now() - lastProcessReload.getTime() > AUTOPROMPT_BIOMETRICS_PROCESS_RELOAD_DELAY
|
||||
) {
|
||||
// Firefox extension closes the popup when unfocused during biometric unlock, pop out the window to prevent infinite loop.
|
||||
if (this.platformUtilsService.getDevice() === DeviceType.FirefoxExtension) {
|
||||
await this.lockComponentService.popOutBrowserExtension();
|
||||
this.shouldClosePopout = true;
|
||||
}
|
||||
this.loading = false;
|
||||
await this.unlockViaBiometrics();
|
||||
}
|
||||
}
|
||||
@@ -585,7 +594,10 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
// If we do not have any saved policies, attempt to load them from the service
|
||||
if (this.enforcedMasterPasswordOptions == undefined) {
|
||||
this.enforcedMasterPasswordOptions = await firstValueFrom(
|
||||
this.policyService.masterPasswordPolicyOptions$(),
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -604,9 +616,17 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
// Vault can be de-synced since notifications get ignored while locked. Need to check whether sync is required using the sync service.
|
||||
const startSync = new Date().getTime();
|
||||
// TODO: This should probably not be blocking
|
||||
await this.syncService.fullSync(false);
|
||||
this.logService.info(`[LockComponent] Sync took ${new Date().getTime() - startSync}ms`);
|
||||
|
||||
const startRegeneration = new Date().getTime();
|
||||
// TODO: This should probably not be blocking
|
||||
await this.userAsymmetricKeysRegenerationService.regenerateIfNeeded(this.activeAccount.id);
|
||||
this.logService.info(
|
||||
`[LockComponent] Private key regeneration took ${new Date().getTime() - startRegeneration}ms`,
|
||||
);
|
||||
|
||||
if (this.clientType === "browser") {
|
||||
const previousUrl = this.lockComponentService.getPreviousUrl();
|
||||
@@ -629,6 +649,13 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
const successRoute = clientTypeToSuccessRouteRecord[this.clientType];
|
||||
await this.router.navigate([successRoute]);
|
||||
}
|
||||
|
||||
if (
|
||||
this.shouldClosePopout &&
|
||||
this.platformUtilsService.getDevice() === DeviceType.FirefoxExtension
|
||||
) {
|
||||
this.lockComponentService.closeBrowserExtensionPopout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,18 @@ export abstract class LockComponentService {
|
||||
// Extension
|
||||
abstract getBiometricsError(error: any): string | null;
|
||||
abstract getPreviousUrl(): string | null;
|
||||
/**
|
||||
* Opens the current page in a popout window if not already in a popout or the sidebar.
|
||||
* If already in a popout or sidebar, does nothing.
|
||||
* @throws Error if execution context is not a browser extension.
|
||||
*/
|
||||
abstract popOutBrowserExtension(): Promise<void>;
|
||||
/**
|
||||
* Closes the current popout window if in a popout.
|
||||
* If not in a popout, does nothing.
|
||||
* @throws Error if execution context is not a browser extension.
|
||||
*/
|
||||
abstract closeBrowserExtensionPopout(): void;
|
||||
|
||||
// Desktop only
|
||||
abstract isWindowVisible(): Promise<boolean>;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<bit-dialog
|
||||
dialogSize="large"
|
||||
[loading]="loading"
|
||||
[title]="'trustOrganization' | i18n"
|
||||
[subtitle]="params.name"
|
||||
>
|
||||
<ng-container bitDialogContent>
|
||||
<bit-callout type="warning">{{ "orgTrustWarning" | i18n }}</bit-callout>
|
||||
<p bitTypography="body1">
|
||||
{{ "fingerprintPhrase" | i18n }} <code>{{ fingerprint }}</code>
|
||||
</p>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button buttonType="primary" bitButton bitFormButton type="button" (click)="submit()">
|
||||
<span>{{ "trust" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton bitFormButton buttonType="secondary" type="button" bitDialogClose>
|
||||
{{ "doNotTrust" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
@@ -0,0 +1,94 @@
|
||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit, Inject } from "@angular/core";
|
||||
import { FormBuilder, FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CalloutModule,
|
||||
DialogModule,
|
||||
DialogService,
|
||||
FormFieldModule,
|
||||
LinkModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
type AccountRecoveryTrustDialogData = {
|
||||
/** display name of the user */
|
||||
name: string;
|
||||
/** org id */
|
||||
orgId: string;
|
||||
/** org public key */
|
||||
publicKey: Uint8Array;
|
||||
};
|
||||
@Component({
|
||||
selector: "account-recovery-trust",
|
||||
templateUrl: "account-recovery-trust.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
DialogModule,
|
||||
ButtonModule,
|
||||
LinkModule,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
FormFieldModule,
|
||||
AsyncActionsModule,
|
||||
FormsModule,
|
||||
CalloutModule,
|
||||
],
|
||||
})
|
||||
export class AccountRecoveryTrustComponent implements OnInit {
|
||||
loading = true;
|
||||
fingerprint: string = "";
|
||||
confirmForm = this.formBuilder.group({});
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected params: AccountRecoveryTrustDialogData,
|
||||
private formBuilder: FormBuilder,
|
||||
private keyService: KeyService,
|
||||
private logService: LogService,
|
||||
private dialogRef: DialogRef<boolean>,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
try {
|
||||
const fingerprint = await this.keyService.getFingerprint(
|
||||
this.params.orgId,
|
||||
this.params.publicKey,
|
||||
);
|
||||
if (fingerprint != null) {
|
||||
this.fingerprint = fingerprint.join("-");
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
/**
|
||||
* Strongly typed helper to open a AccountRecoveryTrustComponent
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param data The data to pass to the dialog
|
||||
*/
|
||||
static open(dialogService: DialogService, data: AccountRecoveryTrustDialogData) {
|
||||
return dialogService.open<boolean, AccountRecoveryTrustDialogData>(
|
||||
AccountRecoveryTrustComponent,
|
||||
{
|
||||
data,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<bit-dialog
|
||||
dialogSize="large"
|
||||
[loading]="loading"
|
||||
[title]="'trustUser' | i18n"
|
||||
[subtitle]="params.name"
|
||||
>
|
||||
<ng-container bitDialogContent>
|
||||
<bit-callout type="warning">{{ "emergencyAccessTrustWarning" | i18n }}</bit-callout>
|
||||
<p bitTypography="body1">
|
||||
{{ "fingerprintEnsureIntegrityVerify" | i18n }}
|
||||
<a
|
||||
bitLink
|
||||
href="https://bitwarden.com/help/fingerprint-phrase/"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ "learnMore" | i18n }}</a
|
||||
>
|
||||
</p>
|
||||
<p bitTypography="body1">
|
||||
<code>{{ fingerprint }}</code>
|
||||
</p>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button buttonType="primary" bitButton bitFormButton type="button" (click)="submit()">
|
||||
<span>{{ "trust" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton bitFormButton buttonType="secondary" type="button" bitDialogClose>
|
||||
{{ "doNotTrust" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
@@ -0,0 +1,94 @@
|
||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit, Inject } from "@angular/core";
|
||||
import { FormBuilder, FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
CalloutModule,
|
||||
DialogModule,
|
||||
DialogService,
|
||||
FormFieldModule,
|
||||
LinkModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
type EmergencyAccessTrustDialogData = {
|
||||
/** display name of the user */
|
||||
name: string;
|
||||
/** userid of the user */
|
||||
userId: string;
|
||||
/** user public key */
|
||||
publicKey: Uint8Array;
|
||||
};
|
||||
@Component({
|
||||
selector: "emergency-access-trust",
|
||||
templateUrl: "emergency-access-trust.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
DialogModule,
|
||||
ButtonModule,
|
||||
LinkModule,
|
||||
TypographyModule,
|
||||
ReactiveFormsModule,
|
||||
FormFieldModule,
|
||||
AsyncActionsModule,
|
||||
FormsModule,
|
||||
CalloutModule,
|
||||
],
|
||||
})
|
||||
export class EmergencyAccessTrustComponent implements OnInit {
|
||||
loading = true;
|
||||
fingerprint: string = "";
|
||||
confirmForm = this.formBuilder.group({});
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected params: EmergencyAccessTrustDialogData,
|
||||
private formBuilder: FormBuilder,
|
||||
private keyService: KeyService,
|
||||
private logService: LogService,
|
||||
private dialogRef: DialogRef<boolean, EmergencyAccessTrustComponent>,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
try {
|
||||
const fingerprint = await this.keyService.getFingerprint(
|
||||
this.params.userId,
|
||||
this.params.publicKey,
|
||||
);
|
||||
if (fingerprint != null) {
|
||||
this.fingerprint = fingerprint.join("-");
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
/**
|
||||
* Strongly typed helper to open a EmergencyAccessTrustComponent
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param data The data to pass to the dialog
|
||||
*/
|
||||
static open(dialogService: DialogService, data: EmergencyAccessTrustDialogData) {
|
||||
return dialogService.open<boolean, EmergencyAccessTrustDialogData>(
|
||||
EmergencyAccessTrustComponent,
|
||||
{
|
||||
data,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user