1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 05:43:41 +00:00

[PM-3763] remove Sweet Alert from desktop and browser (#6138)

* update desktop and browser swal references to use CL

* rename bit-dialog-close

* share fingerprint dialog between desktop and browser

* apply code review

* format fingerprint in template

* apply code review

* fix button color

* fix button types

* update var names

* close awaitDesktop dialog on success AND error

* add DialogService to NativeMessageHandlerService deps

* wrap browser message dialogs in ngZone.run

* wrap native messaging handler in ngzone.run

* apply code review

* fix async ngzone

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
Will Martin
2023-09-11 14:54:23 -04:00
committed by GitHub
parent 2323509dee
commit f999e2cea9
20 changed files with 268 additions and 118 deletions

View File

@@ -422,9 +422,10 @@ export class NativeMessagingBackground {
} }
private async showFingerprintDialog() { private async showFingerprintDialog() {
const fingerprint = ( const fingerprint = await this.cryptoService.getFingerprint(
await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey) await this.stateService.getUserId(),
).join(" "); this.publicKey
);
this.messagingService.send("showNativeMessagingFinterprintDialog", { this.messagingService.send("showNativeMessagingFinterprintDialog", {
fingerprint: fingerprint, fingerprint: fingerprint,

View File

@@ -9,8 +9,7 @@ import {
import { DomSanitizer } from "@angular/platform-browser"; import { DomSanitizer } from "@angular/platform-browser";
import { NavigationEnd, Router, RouterOutlet } from "@angular/router"; import { NavigationEnd, Router, RouterOutlet } from "@angular/router";
import { IndividualConfig, ToastrService } from "ngx-toastr"; import { IndividualConfig, ToastrService } from "ngx-toastr";
import { filter, concatMap, Subject, takeUntil } from "rxjs"; import { filter, concatMap, Subject, takeUntil, firstValueFrom } from "rxjs";
import Swal from "sweetalert2";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
@@ -23,6 +22,7 @@ import { BrowserApi } from "../platform/browser/browser-api";
import { BrowserStateService } from "../platform/services/abstractions/browser-state.service"; import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";
import { routerTransition } from "./app-routing.animations"; import { routerTransition } from "./app-routing.animations";
import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component";
@Component({ @Component({
selector: "app-root", selector: "app-root",
@@ -113,10 +113,10 @@ export class AppComponent implements OnInit, OnDestroy {
}); });
} }
} else if (msg.command === "showDialog") { } else if (msg.command === "showDialog") {
await this.showDialog(msg); await this.ngZone.run(() => this.showDialog(msg));
} else if (msg.command === "showNativeMessagingFinterprintDialog") { } else if (msg.command === "showNativeMessagingFinterprintDialog") {
// TODO: Should be refactored to live in another service. // TODO: Should be refactored to live in another service.
await this.showNativeMessagingFingerprintDialog(msg); await this.ngZone.run(() => this.showNativeMessagingFingerprintDialog(msg));
} else if (msg.command === "showToast") { } else if (msg.command === "showToast") {
this.ngZone.run(() => { this.ngZone.run(() => {
this.showToast(msg); this.showToast(msg);
@@ -242,19 +242,11 @@ export class AppComponent implements OnInit, OnDestroy {
} }
private async showNativeMessagingFingerprintDialog(msg: any) { private async showNativeMessagingFingerprintDialog(msg: any) {
await Swal.fire({ const dialogRef = DesktopSyncVerificationDialogComponent.open(this.dialogService, {
heightAuto: false, fingerprint: msg.fingerprint,
buttonsStyling: false,
icon: "warning",
iconHtml: '<i class="swal-custom-icon bwi bwi-exclamation-triangle text-warning"></i>',
html: `${this.i18nService.t("desktopIntegrationVerificationText")}<br><br><strong>${
msg.fingerprint
}</strong>`,
titleText: this.i18nService.t("desktopSyncVerificationTitle"),
showConfirmButton: true,
confirmButtonText: this.i18nService.t("ok"),
timer: 300000,
}); });
return firstValueFrom(dialogRef.closed);
} }
private async clearComponentStates() { private async clearComponentStates() {

View File

@@ -0,0 +1,18 @@
<bit-simple-dialog>
<span bitDialogTitle>
{{ "desktopSyncVerificationTitle" | i18n }}
</span>
<span bitDialogContent>
<p>
{{ "desktopIntegrationVerificationText" | i18n }}
</p>
<p>
<strong>{{ params.fingerprint.join("-") }}</strong>
</p>
</span>
<ng-container bitDialogFooter>
<button bitButton type="button" buttonType="primary" bitDialogClose>
{{ "ok" | i18n }}
</button>
</ng-container>
</bit-simple-dialog>

View File

@@ -0,0 +1,24 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
export type DesktopSyncVerificationDialogParams = {
fingerprint: string[];
};
@Component({
templateUrl: "desktop-sync-verification-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class DesktopSyncVerificationDialogComponent {
constructor(@Inject(DIALOG_DATA) protected params: DesktopSyncVerificationDialogParams) {}
static open(dialogService: DialogService, data: DesktopSyncVerificationDialogParams) {
return dialogService.open(DesktopSyncVerificationDialogComponent, {
data,
});
}
}

View File

@@ -0,0 +1,11 @@
<bit-simple-dialog>
<span bitDialogTitle>{{ "awaitDesktop" | i18n }}</span>
<span bitDialogContent>
{{ "awaitDesktopDesc" | i18n }}
</span>
<ng-container bitDialogFooter>
<button bitButton type="button" buttonType="secondary" [bitDialogClose]="true">
{{ "close" | i18n }}
</button>
</ng-container>
</bit-simple-dialog>

View File

@@ -0,0 +1,17 @@
import { Component } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
@Component({
templateUrl: "await-desktop-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class AwaitDesktopDialogComponent {
static open(dialogService: DialogService) {
return dialogService.open<boolean>(AwaitDesktopDialogComponent, {
disableClose: true,
});
}
}

View File

@@ -15,9 +15,9 @@ import {
switchMap, switchMap,
takeUntil, takeUntil,
} from "rxjs"; } from "rxjs";
import Swal from "sweetalert2";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
import { FingerprintDialogComponent } from "@bitwarden/auth";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@@ -39,6 +39,7 @@ import { SetPinComponent } from "../components/set-pin.component";
import { PopupUtilsService } from "../services/popup-utils.service"; import { PopupUtilsService } from "../services/popup-utils.service";
import { AboutComponent } from "./about.component"; import { AboutComponent } from "./about.component";
import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component";
const RateUrls = { const RateUrls = {
[DeviceType.ChromeExtension]: [DeviceType.ChromeExtension]:
@@ -361,25 +362,15 @@ export class SettingsComponent implements OnInit {
return; return;
} }
const submitted = Swal.fire({ const awaitDesktopDialogRef = AwaitDesktopDialogComponent.open(this.dialogService);
heightAuto: false, const awaitDesktopDialogClosed = firstValueFrom(awaitDesktopDialogRef.closed);
buttonsStyling: false,
titleText: this.i18nService.t("awaitDesktop"),
text: this.i18nService.t("awaitDesktopDesc"),
icon: "info",
iconHtml: '<i class="swal-custom-icon bwi bwi-info-circle text-info"></i>',
showCancelButton: true,
cancelButtonText: this.i18nService.t("cancel"),
showConfirmButton: false,
allowOutsideClick: false,
});
await this.stateService.setBiometricAwaitingAcceptance(true); await this.stateService.setBiometricAwaitingAcceptance(true);
await this.cryptoService.refreshAdditionalKeys(); await this.cryptoService.refreshAdditionalKeys();
await Promise.race([ await Promise.race([
submitted.then(async (result) => { awaitDesktopDialogClosed.then(async (result) => {
if (result.dismiss === Swal.DismissReason.cancel) { if (result) {
this.form.controls.biometric.setValue(false); this.form.controls.biometric.setValue(false);
await this.stateService.setBiometricAwaitingAcceptance(null); await this.stateService.setBiometricAwaitingAcceptance(null);
} }
@@ -388,8 +379,6 @@ export class SettingsComponent implements OnInit {
.authenticateBiometric() .authenticateBiometric()
.then((result) => { .then((result) => {
this.form.controls.biometric.setValue(result); this.form.controls.biometric.setValue(result);
Swal.close();
if (!result) { if (!result) {
this.platformUtilsService.showToast( this.platformUtilsService.showToast(
"error", "error",
@@ -411,6 +400,9 @@ export class SettingsComponent implements OnInit {
cancelButtonText: null, cancelButtonText: null,
type: "danger", type: "danger",
}); });
})
.finally(() => {
awaitDesktopDialogRef.close(false);
}), }),
]); ]);
} else { } else {
@@ -497,27 +489,12 @@ export class SettingsComponent implements OnInit {
const fingerprint = await this.cryptoService.getFingerprint( const fingerprint = await this.cryptoService.getFingerprint(
await this.stateService.getUserId() await this.stateService.getUserId()
); );
const p = document.createElement("p");
p.innerText = this.i18nService.t("yourAccountsFingerprint") + ":";
const p2 = document.createElement("p");
p2.innerText = fingerprint.join("-");
const div = document.createElement("div");
div.appendChild(p);
div.appendChild(p2);
const result = await Swal.fire({ const dialogRef = FingerprintDialogComponent.open(this.dialogService, {
heightAuto: false, fingerprint,
buttonsStyling: false,
html: div,
showCancelButton: true,
cancelButtonText: this.i18nService.t("close"),
showConfirmButton: true,
confirmButtonText: this.i18nService.t("learnMore"),
}); });
if (result.value) { return firstValueFrom(dialogRef.closed);
this.platformUtilsService.launchUri("https://bitwarden.com/help/fingerprint-phrase/");
}
} }
rate() { rate() {

View File

@@ -16,6 +16,7 @@ import { firstValueFrom, Subject, takeUntil } from "rxjs";
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
import { FingerprintDialogComponent } from "@bitwarden/auth";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
@@ -244,18 +245,8 @@ export class AppComponent implements OnInit, OnDestroy {
const fingerprint = await this.cryptoService.getFingerprint( const fingerprint = await this.cryptoService.getFingerprint(
await this.stateService.getUserId() await this.stateService.getUserId()
); );
const result = await this.dialogService.openSimpleDialog({ const dialogRef = FingerprintDialogComponent.open(this.dialogService, { fingerprint });
title: { key: "fingerprintPhrase" }, await firstValueFrom(dialogRef.closed);
content:
this.i18nService.t("yourAccountsFingerprint") + ":\n" + fingerprint.join("-"),
acceptButtonText: { key: "learnMore" },
cancelButtonText: { key: "close" },
type: "info",
});
if (result) {
this.platformUtilsService.launchUri("https://bitwarden.com/help/fingerprint-phrase/");
}
break; break;
} }
case "deleteAccount": case "deleteAccount":

View File

@@ -0,0 +1,19 @@
<bit-simple-dialog>
<span bitDialogTitle>
{{ "verifyBrowserTitle" | i18n }}
</span>
<span bitDialogContent>
<p>{{ "verifyBrowserDesc" | i18n }}</p>
<p>
<strong>{{ params.fingerprint.join("-") }}</strong>
</p>
</span>
<ng-container bitDialogFooter>
<button bitButton type="button" buttonType="primary" [bitDialogClose]="true">
{{ "approve" | i18n }}
</button>
<button bitButton type="button" buttonType="secondary" [bitDialogClose]="false">
{{ "cancel" | i18n }}
</button>
</ng-container>
</bit-simple-dialog>

View File

@@ -0,0 +1,25 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
export type BrowserSyncVerificationDialogParams = {
fingerprint: string[];
};
@Component({
templateUrl: "browser-sync-verification-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class BrowserSyncVerificationDialogComponent {
constructor(@Inject(DIALOG_DATA) protected params: BrowserSyncVerificationDialogParams) {}
static open(dialogService: DialogService, data: BrowserSyncVerificationDialogParams) {
return dialogService.open(BrowserSyncVerificationDialogComponent, {
data,
disableClose: true,
});
}
}

View File

@@ -0,0 +1,18 @@
<bit-simple-dialog>
<span bitDialogTitle>
{{ "verifyNativeMessagingConnectionTitle" | i18n : data.applicationName }}:
</span>
<span bitDialogContent>
{{ "verifyNativeMessagingConnectionDesc" | i18n }}
<br />
{{ "verifyNativeMessagingConnectionWarning" | i18n }}
</span>
<ng-container bitDialogFooter>
<button bitButton type="button" buttonType="primary" [bitDialogClose]="true">
{{ "yes" | i18n }}
</button>
<button bitButton type="button" buttonType="secondary" [bitDialogClose]="false">
{{ "no" | i18n }}
</button>
</ng-container>
</bit-simple-dialog>

View File

@@ -0,0 +1,24 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
export type VerifyNativeMessagingDialogData = {
applicationName: string;
};
@Component({
templateUrl: "verify-native-messaging-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class VerifyNativeMessagingDialogComponent {
constructor(@Inject(DIALOG_DATA) protected data: VerifyNativeMessagingDialogData) {}
static open(dialogService: DialogService, data: VerifyNativeMessagingDialogData) {
return dialogService.open<boolean>(VerifyNativeMessagingDialogComponent, {
data,
});
}
}

View File

@@ -169,6 +169,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
MessagingServiceAbstraction, MessagingServiceAbstraction,
I18nServiceAbstraction, I18nServiceAbstraction,
EncryptedMessageHandlerService, EncryptedMessageHandlerService,
DialogService,
], ],
}, },
{ {

View File

@@ -1,6 +1,6 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { ipcRenderer } from "electron"; import { ipcRenderer } from "electron";
import Swal from "sweetalert2"; import { firstValueFrom } from "rxjs";
import { NativeMessagingVersion } from "@bitwarden/common/enums"; import { NativeMessagingVersion } from "@bitwarden/common/enums";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
@@ -11,7 +11,9 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { StateService } from "@bitwarden/common/platform/services/state.service"; import { StateService } from "@bitwarden/common/platform/services/state.service";
import { DialogService } from "@bitwarden/components";
import { VerifyNativeMessagingDialogComponent } from "../app/components/verify-native-messaging-dialog.component";
import { DecryptedCommandData } from "../models/native-messaging/decrypted-command-data"; import { DecryptedCommandData } from "../models/native-messaging/decrypted-command-data";
import { EncryptedMessage } from "../models/native-messaging/encrypted-message"; import { EncryptedMessage } from "../models/native-messaging/encrypted-message";
import { EncryptedMessageResponse } from "../models/native-messaging/encrypted-message-response"; import { EncryptedMessageResponse } from "../models/native-messaging/encrypted-message-response";
@@ -33,7 +35,8 @@ export class NativeMessageHandlerService {
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private messagingService: MessagingService, private messagingService: MessagingService,
private i18nService: I18nService, private i18nService: I18nService,
private encryptedMessageHandlerService: EncryptedMessageHandlerService private encryptedMessageHandlerService: EncryptedMessageHandlerService,
private dialogService: DialogService
) {} ) {}
async handleMessage(message: Message) { async handleMessage(message: Message) {
@@ -87,21 +90,12 @@ export class NativeMessageHandlerService {
// Ask for confirmation from user // Ask for confirmation from user
this.messagingService.send("setFocus"); this.messagingService.send("setFocus");
const submitted = await Swal.fire({
heightAuto: false,
titleText: this.i18nService.t("verifyNativeMessagingConnectionTitle", applicationName),
html: `${this.i18nService.t("verifyNativeMessagingConnectionDesc")}<br>${this.i18nService.t(
"verifyNativeMessagingConnectionWarning"
)}`,
showCancelButton: true,
cancelButtonText: this.i18nService.t("no"),
showConfirmButton: true,
confirmButtonText: this.i18nService.t("yes"),
allowOutsideClick: false,
focusCancel: true,
});
if (submitted.value !== true) { const nativeMessagingVerified = await firstValueFrom(
VerifyNativeMessagingDialogComponent.open(this.dialogService, { applicationName }).closed
);
if (nativeMessagingVerified !== true) {
this.sendResponse({ this.sendResponse({
messageId: messageId, messageId: messageId,
version: NativeMessagingVersion.Latest, version: NativeMessagingVersion.Latest,

View File

@@ -1,7 +1,6 @@
import { Injectable } from "@angular/core"; import { Injectable, NgZone } from "@angular/core";
import { ipcRenderer } from "electron"; import { ipcRenderer } from "electron";
import { firstValueFrom } from "rxjs"; import { firstValueFrom } from "rxjs";
import Swal from "sweetalert2";
import { KeySuffixOptions } from "@bitwarden/common/enums"; import { KeySuffixOptions } from "@bitwarden/common/enums";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
@@ -14,7 +13,9 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { DialogService } from "@bitwarden/components";
import { BrowserSyncVerificationDialogComponent } from "../app/components/browser-sync-verification-dialog.component";
import { LegacyMessage } from "../models/native-messaging/legacy-message"; import { LegacyMessage } from "../models/native-messaging/legacy-message";
import { LegacyMessageWrapper } from "../models/native-messaging/legacy-message-wrapper"; import { LegacyMessageWrapper } from "../models/native-messaging/legacy-message-wrapper";
import { Message } from "../models/native-messaging/message"; import { Message } from "../models/native-messaging/message";
@@ -36,7 +37,9 @@ export class NativeMessagingService {
private i18nService: I18nService, private i18nService: I18nService,
private messagingService: MessagingService, private messagingService: MessagingService,
private stateService: StateService, private stateService: StateService,
private nativeMessageHandler: NativeMessageHandlerService private nativeMessageHandler: NativeMessageHandlerService,
private dialogService: DialogService,
private ngZone: NgZone
) {} ) {}
init() { init() {
@@ -69,27 +72,20 @@ export class NativeMessagingService {
if (await this.stateService.getEnableBrowserIntegrationFingerprint()) { if (await this.stateService.getEnableBrowserIntegrationFingerprint()) {
ipcRenderer.send("nativeMessagingReply", { command: "verifyFingerprint", appId: appId }); ipcRenderer.send("nativeMessagingReply", { command: "verifyFingerprint", appId: appId });
const fingerprint = ( const fingerprint = await this.cryptoService.getFingerprint(
await this.cryptoService.getFingerprint( await this.stateService.getUserId(),
await this.stateService.getUserId(), remotePublicKey
remotePublicKey );
)
).join(" ");
this.messagingService.send("setFocus"); this.messagingService.send("setFocus");
// Await confirmation that fingerprint is correct const dialogRef = this.ngZone.run(() =>
const submitted = await Swal.fire({ BrowserSyncVerificationDialogComponent.open(this.dialogService, { fingerprint })
titleText: this.i18nService.t("verifyBrowserTitle"), );
html: `${this.i18nService.t("verifyBrowserDesc")}<br><br><strong>${fingerprint}</strong>`,
showCancelButton: true,
cancelButtonText: this.i18nService.t("cancel"),
showConfirmButton: true,
confirmButtonText: this.i18nService.t("approve"),
allowOutsideClick: false,
});
if (submitted.value !== true) { const browserSyncVerified = await firstValueFrom(dialogRef.closed);
if (browserSyncVerified !== true) {
return; return;
} }
} }
@@ -127,13 +123,15 @@ export class NativeMessagingService {
if (!(await this.stateService.getBiometricUnlock({ userId: message.userId }))) { if (!(await this.stateService.getBiometricUnlock({ userId: message.userId }))) {
this.send({ command: "biometricUnlock", response: "not enabled" }, appId); this.send({ command: "biometricUnlock", response: "not enabled" }, appId);
return await Swal.fire({ return this.ngZone.run(() =>
title: this.i18nService.t("biometricsNotEnabledTitle"), this.dialogService.openSimpleDialog({
text: this.i18nService.t("biometricsNotEnabledDesc"), type: "warning",
showCancelButton: true, title: { key: "biometricsNotEnabledTitle" },
cancelButtonText: this.i18nService.t("cancel"), content: { key: "biometricsNotEnabledDesc" },
showConfirmButton: false, cancelButtonText: null,
}); acceptButtonText: { key: "cancel" },
})
);
} }
const userKey = await this.cryptoService.getUserKeyFromStorage( const userKey = await this.cryptoService.getUserKeyFromStorage(

View File

@@ -69,13 +69,7 @@
<button bitButton buttonType="primary" bitFormButton type="submit"> <button bitButton buttonType="primary" bitFormButton type="submit">
{{ "save" | i18n }} {{ "save" | i18n }}
</button> </button>
<button <button bitButton buttonType="secondary" type="button" [bitDialogClose]="ResultType.Canceled">
bitButton
buttonType="secondary"
type="button"
bitDialogClose
[bit-dialog-close]="ResultType.Canceled"
>
{{ "cancel" | i18n }} {{ "cancel" | i18n }}
</button> </button>
<button <button

View File

@@ -0,0 +1,23 @@
<bit-simple-dialog>
<i bitDialogIcon class="bwi bwi-info-circle tw-text-3xl" aria-hidden="true"></i>
<span bitDialogTitle>{{ "yourAccountsFingerprint" | i18n }}:</span>
<span bitDialogContent>
<strong>{{ data.fingerprint.join("-") }}</strong>
</span>
<ng-container bitDialogFooter>
<a
bitButton
href="https://bitwarden.com/help/fingerprint-phrase/"
target="_blank"
rel="noopener"
buttonType="primary"
bitDialogClose
>
{{ "learnMore" | i18n }}
<i class="bwi bwi-external-link bwi-fw" aria-hidden="true"></i>
</a>
<button bitButton type="button" buttonType="secondary" bitDialogClose>
{{ "close" | i18n }}
</button>
</ng-container>
</bit-simple-dialog>

View File

@@ -0,0 +1,22 @@
import { DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ButtonModule, DialogModule, DialogService } from "@bitwarden/components";
export type FingerprintDialogData = {
fingerprint: string[];
};
@Component({
templateUrl: "fingerprint-dialog.component.html",
standalone: true,
imports: [JslibModule, ButtonModule, DialogModule],
})
export class FingerprintDialogComponent {
constructor(@Inject(DIALOG_DATA) protected data: FingerprintDialogData) {}
static open(dialogService: DialogService, data: FingerprintDialogData) {
return dialogService.open(FingerprintDialogComponent, { data });
}
}

View File

@@ -0,0 +1 @@
export * from "./components/fingerprint-dialog.component";

View File

@@ -5,9 +5,9 @@ import { Directive, HostListener, Input, Optional } from "@angular/core";
selector: "[bitDialogClose]", selector: "[bitDialogClose]",
}) })
export class DialogCloseDirective { export class DialogCloseDirective {
@Input("bit-dialog-close") dialogResult: any; @Input("bitDialogClose") dialogResult: any;
constructor(@Optional() public dialogRef: DialogRef<any>) {} constructor(@Optional() public dialogRef: DialogRef) {}
@HostListener("click") close(): void { @HostListener("click") close(): void {
this.dialogRef.close(this.dialogResult); this.dialogRef.close(this.dialogResult);