diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index 815109c549..179abf5a8c 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -9,8 +9,7 @@ import { import { DomSanitizer } from "@angular/platform-browser"; import { NavigationEnd, Router, RouterOutlet } from "@angular/router"; import { IndividualConfig, ToastrService } from "ngx-toastr"; -import { filter, concatMap, Subject, takeUntil } from "rxjs"; -import Swal from "sweetalert2"; +import { filter, concatMap, Subject, takeUntil, firstValueFrom } from "rxjs"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.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 { routerTransition } from "./app-routing.animations"; +import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component"; @Component({ selector: "app-root", @@ -242,19 +242,11 @@ export class AppComponent implements OnInit, OnDestroy { } private async showNativeMessagingFingerprintDialog(msg: any) { - await Swal.fire({ - heightAuto: false, - buttonsStyling: false, - icon: "warning", - iconHtml: '', - html: `${this.i18nService.t("desktopIntegrationVerificationText")}

${ - msg.fingerprint - }`, - titleText: this.i18nService.t("desktopSyncVerificationTitle"), - showConfirmButton: true, - confirmButtonText: this.i18nService.t("ok"), - timer: 300000, + const dialogRef = DesktopSyncVerificationDialogComponent.open(this.dialogService, { + fingerprint: msg.fingerprint, }); + + return firstValueFrom(dialogRef.closed); } private async clearComponentStates() { diff --git a/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.html b/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.html new file mode 100644 index 0000000000..d9bb0e33b2 --- /dev/null +++ b/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.html @@ -0,0 +1,15 @@ + + + {{ "desktopSyncVerificationTitle" | i18n }} + + + {{ "desktopIntegrationVerificationText" | i18n }} +

+ {{ params.fingerprint }} +
+ + + +
diff --git a/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.ts b/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.ts new file mode 100644 index 0000000000..4e5bbe18f7 --- /dev/null +++ b/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.ts @@ -0,0 +1,29 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { + AsyncActionsModule, + 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, AsyncActionsModule], +}) +export class DesktopSyncVerificationDialogComponent { + constructor(@Inject(DIALOG_DATA) protected params: DesktopSyncVerificationDialogParams) {} + + static open(dialogService: DialogService, data: DesktopSyncVerificationDialogParams) { + return dialogService.open(DesktopSyncVerificationDialogComponent, { + data, + }); + } +} diff --git a/apps/browser/src/popup/settings/await-desktop-dialog.component.html b/apps/browser/src/popup/settings/await-desktop-dialog.component.html new file mode 100644 index 0000000000..765bc3d140 --- /dev/null +++ b/apps/browser/src/popup/settings/await-desktop-dialog.component.html @@ -0,0 +1,11 @@ + + {{ "awaitDesktop" | i18n }}: + + {{ "awaitDesktopDesc" | i18n }} + + + + + diff --git a/apps/browser/src/popup/settings/await-desktop-dialog.component.ts b/apps/browser/src/popup/settings/await-desktop-dialog.component.ts new file mode 100644 index 0000000000..6bccc927e6 --- /dev/null +++ b/apps/browser/src/popup/settings/await-desktop-dialog.component.ts @@ -0,0 +1,22 @@ +import { Component } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { + AsyncActionsModule, + ButtonModule, + DialogModule, + DialogService, +} from "@bitwarden/components"; + +@Component({ + templateUrl: "await-desktop-dialog.component.html", + standalone: true, + imports: [JslibModule, ButtonModule, DialogModule, AsyncActionsModule], +}) +export class AwaitDesktopDialogComponent { + static open(dialogService: DialogService) { + return dialogService.open(AwaitDesktopDialogComponent, { + disableClose: true, + }); + } +} diff --git a/apps/browser/src/popup/settings/fingerprint-dialog.component.html b/apps/browser/src/popup/settings/fingerprint-dialog.component.html new file mode 100644 index 0000000000..c6b806ee03 --- /dev/null +++ b/apps/browser/src/popup/settings/fingerprint-dialog.component.html @@ -0,0 +1,22 @@ + + {{ "yourAccountsFingerprint" | i18n }}: + + {{ data.fingerprint }} + + + + + {{ "learnMore" | i18n }} + + + diff --git a/apps/browser/src/popup/settings/fingerprint-dialog.component.ts b/apps/browser/src/popup/settings/fingerprint-dialog.component.ts new file mode 100644 index 0000000000..8156219083 --- /dev/null +++ b/apps/browser/src/popup/settings/fingerprint-dialog.component.ts @@ -0,0 +1,33 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { + AsyncActionsModule, + ButtonModule, + DialogModule, + DialogService, +} from "@bitwarden/components"; + +export type FingerprintDialogData = { + fingerprint: string; +}; + +@Component({ + templateUrl: "fingerprint-dialog.component.html", + standalone: true, + imports: [JslibModule, ButtonModule, DialogModule, AsyncActionsModule], +}) +export class FingerprintDialogComponent { + constructor( + @Inject(DIALOG_DATA) protected data: FingerprintDialogData, + private cryptoService: CryptoService, + private stateService: StateService + ) {} + + static open(dialogService: DialogService, data: FingerprintDialogData) { + return dialogService.open(FingerprintDialogComponent, { data }); + } +} diff --git a/apps/browser/src/popup/settings/settings.component.ts b/apps/browser/src/popup/settings/settings.component.ts index 30a1f03eac..965a74c3f7 100644 --- a/apps/browser/src/popup/settings/settings.component.ts +++ b/apps/browser/src/popup/settings/settings.component.ts @@ -15,7 +15,6 @@ import { switchMap, takeUntil, } from "rxjs"; -import Swal from "sweetalert2"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; @@ -39,6 +38,8 @@ import { SetPinComponent } from "../components/set-pin.component"; import { PopupUtilsService } from "../services/popup-utils.service"; import { AboutComponent } from "./about.component"; +import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component"; +import { FingerprintDialogComponent } from "./fingerprint-dialog.component"; const RateUrls = { [DeviceType.ChromeExtension]: @@ -361,25 +362,15 @@ export class SettingsComponent implements OnInit { return; } - const submitted = Swal.fire({ - heightAuto: false, - buttonsStyling: false, - titleText: this.i18nService.t("awaitDesktop"), - text: this.i18nService.t("awaitDesktopDesc"), - icon: "info", - iconHtml: '', - showCancelButton: true, - cancelButtonText: this.i18nService.t("cancel"), - showConfirmButton: false, - allowOutsideClick: false, - }); + const awaitDesktopDialogRef = AwaitDesktopDialogComponent.open(this.dialogService); + const awaitDesktopDialogClosed = firstValueFrom(awaitDesktopDialogRef.closed); await this.stateService.setBiometricAwaitingAcceptance(true); await this.cryptoService.refreshAdditionalKeys(); await Promise.race([ - submitted.then(async (result) => { - if (result.dismiss === Swal.DismissReason.cancel) { + awaitDesktopDialogClosed.then(async (result) => { + if (result) { this.form.controls.biometric.setValue(false); await this.stateService.setBiometricAwaitingAcceptance(null); } @@ -389,7 +380,7 @@ export class SettingsComponent implements OnInit { .then((result) => { this.form.controls.biometric.setValue(result); - Swal.close(); + awaitDesktopDialogRef.close(false); if (!result) { this.platformUtilsService.showToast( "error", @@ -494,30 +485,15 @@ export class SettingsComponent implements OnInit { } async fingerprint() { - const fingerprint = await this.cryptoService.getFingerprint( - 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 fingerprint = await this.cryptoService + .getFingerprint(await this.stateService.getUserId()) + .then((rawFingerprint) => rawFingerprint.join("-")); - const result = await Swal.fire({ - heightAuto: false, - buttonsStyling: false, - html: div, - showCancelButton: true, - cancelButtonText: this.i18nService.t("close"), - showConfirmButton: true, - confirmButtonText: this.i18nService.t("learnMore"), + const dialogRef = FingerprintDialogComponent.open(this.dialogService, { + fingerprint, }); - if (result.value) { - this.platformUtilsService.launchUri("https://bitwarden.com/help/fingerprint-phrase/"); - } + return firstValueFrom(dialogRef.closed); } rate() { diff --git a/apps/desktop/src/app/components/browser-sync-verification-dialog.component.html b/apps/desktop/src/app/components/browser-sync-verification-dialog.component.html new file mode 100644 index 0000000000..558e317bea --- /dev/null +++ b/apps/desktop/src/app/components/browser-sync-verification-dialog.component.html @@ -0,0 +1,18 @@ + + + {{ "verifyBrowserTitle" | i18n }} + + + {{ "verifyBrowserDesc" | i18n }} +

+ {{ params.fingerprint }} +
+ + + + +
diff --git a/apps/desktop/src/app/components/browser-sync-verification-dialog.component.ts b/apps/desktop/src/app/components/browser-sync-verification-dialog.component.ts new file mode 100644 index 0000000000..f627380860 --- /dev/null +++ b/apps/desktop/src/app/components/browser-sync-verification-dialog.component.ts @@ -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, + }); + } +} diff --git a/apps/desktop/src/app/components/verify-native-messaging-dialog.component.html b/apps/desktop/src/app/components/verify-native-messaging-dialog.component.html new file mode 100644 index 0000000000..5c35870f77 --- /dev/null +++ b/apps/desktop/src/app/components/verify-native-messaging-dialog.component.html @@ -0,0 +1,18 @@ + + + {{ "verifyNativeMessagingConnectionTitle" | i18n : data.applicationName }}: + + + {{ "verifyNativeMessagingConnectionDesc" | i18n }} +
+ {{ "verifyNativeMessagingConnectionWarning" | i18n }} +
+ + + + +
diff --git a/apps/desktop/src/app/components/verify-native-messaging-dialog.component.ts b/apps/desktop/src/app/components/verify-native-messaging-dialog.component.ts new file mode 100644 index 0000000000..507d566336 --- /dev/null +++ b/apps/desktop/src/app/components/verify-native-messaging-dialog.component.ts @@ -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(VerifyNativeMessagingDialogComponent, { + data, + }); + } +} diff --git a/apps/desktop/src/services/native-message-handler.service.ts b/apps/desktop/src/services/native-message-handler.service.ts index 9f5f1d460d..b9107c0ecd 100644 --- a/apps/desktop/src/services/native-message-handler.service.ts +++ b/apps/desktop/src/services/native-message-handler.service.ts @@ -1,6 +1,6 @@ import { Injectable } from "@angular/core"; import { ipcRenderer } from "electron"; -import Swal from "sweetalert2"; +import { firstValueFrom } from "rxjs"; import { NativeMessagingVersion } from "@bitwarden/common/enums"; 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 { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; 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 { EncryptedMessage } from "../models/native-messaging/encrypted-message"; import { EncryptedMessageResponse } from "../models/native-messaging/encrypted-message-response"; @@ -33,7 +35,8 @@ export class NativeMessageHandlerService { private cryptoFunctionService: CryptoFunctionService, private messagingService: MessagingService, private i18nService: I18nService, - private encryptedMessageHandlerService: EncryptedMessageHandlerService + private encryptedMessageHandlerService: EncryptedMessageHandlerService, + private dialogService: DialogService ) {} async handleMessage(message: Message) { @@ -87,21 +90,12 @@ export class NativeMessageHandlerService { // Ask for confirmation from user this.messagingService.send("setFocus"); - const submitted = await Swal.fire({ - heightAuto: false, - titleText: this.i18nService.t("verifyNativeMessagingConnectionTitle", applicationName), - html: `${this.i18nService.t("verifyNativeMessagingConnectionDesc")}
${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 submitted = await firstValueFrom( + VerifyNativeMessagingDialogComponent.open(this.dialogService, { applicationName }).closed + ); + + if (submitted !== true) { this.sendResponse({ messageId: messageId, version: NativeMessagingVersion.Latest, diff --git a/apps/desktop/src/services/native-messaging.service.ts b/apps/desktop/src/services/native-messaging.service.ts index 3928778f31..646e7bcc50 100644 --- a/apps/desktop/src/services/native-messaging.service.ts +++ b/apps/desktop/src/services/native-messaging.service.ts @@ -1,7 +1,6 @@ import { Injectable } from "@angular/core"; import { ipcRenderer } from "electron"; import { firstValueFrom } from "rxjs"; -import Swal from "sweetalert2"; import { KeySuffixOptions } from "@bitwarden/common/enums"; 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 { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; 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 { LegacyMessageWrapper } from "../models/native-messaging/legacy-message-wrapper"; import { Message } from "../models/native-messaging/message"; @@ -36,7 +37,8 @@ export class NativeMessagingService { private i18nService: I18nService, private messagingService: MessagingService, private stateService: StateService, - private nativeMessageHandler: NativeMessageHandlerService + private nativeMessageHandler: NativeMessageHandlerService, + private dialogService: DialogService ) {} init() { @@ -74,22 +76,15 @@ export class NativeMessagingService { await this.stateService.getUserId(), remotePublicKey ) - ).join(" "); + ).join("-"); this.messagingService.send("setFocus"); - // Await confirmation that fingerprint is correct - const submitted = await Swal.fire({ - titleText: this.i18nService.t("verifyBrowserTitle"), - html: `${this.i18nService.t("verifyBrowserDesc")}

${fingerprint}`, - showCancelButton: true, - cancelButtonText: this.i18nService.t("cancel"), - showConfirmButton: true, - confirmButtonText: this.i18nService.t("approve"), - allowOutsideClick: false, - }); + const submitted = await firstValueFrom( + BrowserSyncVerificationDialogComponent.open(this.dialogService, { fingerprint }).closed + ); - if (submitted.value !== true) { + if (submitted !== true) { return; } } @@ -127,12 +122,12 @@ export class NativeMessagingService { if (!(await this.stateService.getBiometricUnlock({ userId: message.userId }))) { this.send({ command: "biometricUnlock", response: "not enabled" }, appId); - return await Swal.fire({ - title: this.i18nService.t("biometricsNotEnabledTitle"), - text: this.i18nService.t("biometricsNotEnabledDesc"), - showCancelButton: true, - cancelButtonText: this.i18nService.t("cancel"), - showConfirmButton: false, + return this.dialogService.openSimpleDialog({ + type: "warning", + title: { key: "biometricsNotEnabledTitle" }, + content: { key: "biometricsNotEnabledDesc" }, + cancelButtonText: null, + acceptButtonText: { key: "cancel" }, }); }