From 93c11a7dab944e919ad4522a91bf8f1ac86a053b Mon Sep 17 00:00:00 2001
From: aj-rosado <109146700+aj-rosado@users.noreply.github.com>
Date: Mon, 11 Sep 2023 11:37:46 +0100
Subject: [PATCH 01/25] Setting properly the type to verify on SendAddEdit
(#6252)
---
apps/browser/src/tools/popup/send/send-add-edit.component.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/browser/src/tools/popup/send/send-add-edit.component.html b/apps/browser/src/tools/popup/send/send-add-edit.component.html
index 707adaa7a55..11dca222fca 100644
--- a/apps/browser/src/tools/popup/send/send-add-edit.component.html
+++ b/apps/browser/src/tools/popup/send/send-add-edit.component.html
@@ -27,7 +27,7 @@
icon="bwi-external-link bwi-rotate-270 bwi-fw"
[clickable]="true"
title="{{ 'sendFileCalloutHeader' | i18n }}"
- *ngIf="showFilePopoutMessage && send.type === sendType.File && !disableSend"
+ *ngIf="showFilePopoutMessage && type === sendType.File && !disableSend"
(click)="popOutWindow()"
>
{{ "sendLinuxChromiumFileWarning" | i18n }}
From 30d8168c2e5c96739a4c02fa7dc7306911198d32 Mon Sep 17 00:00:00 2001
From: Robyn MacCallum
Date: Mon, 11 Sep 2023 10:40:50 -0400
Subject: [PATCH 02/25] [PM-3600] Try to get key in master password reprompt
check (#6087)
* Add check to hasMasterPasswordAndMasterKeyHash to make sure getMasterKey() has a value
* Try getting or deriving the key on password reprompt
---
.../src/vault/components/password-reprompt.component.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libs/angular/src/vault/components/password-reprompt.component.ts b/libs/angular/src/vault/components/password-reprompt.component.ts
index 0f0fd685b20..1094b379316 100644
--- a/libs/angular/src/vault/components/password-reprompt.component.ts
+++ b/libs/angular/src/vault/components/password-reprompt.component.ts
@@ -27,7 +27,8 @@ export class PasswordRepromptComponent {
}
async submit() {
- if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) {
+ const storedMasterKey = await this.cryptoService.getOrDeriveMasterKey(this.masterPassword);
+ if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, storedMasterKey))) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
From 2323509dee449e33f55c4b1a7106679f37b56d7c Mon Sep 17 00:00:00 2001
From: Daniel James Smith
Date: Mon, 11 Sep 2023 16:41:34 +0200
Subject: [PATCH 03/25] [PM-147] Import error states usability improvements
(#6245)
* Add import error dialog
(cherry picked from commit 518211dae0c2e7d26ea6dbfec77a9066c4262c75)
* Rename ErrorList to ErrorListItem
(cherry picked from commit a7dd643710fa6d68d3d7bb427437dbb84e98a1f2)
---
.../dialog/import-error-dialog.component.html | 29 ++++++++++++++++
.../dialog/import-error-dialog.component.ts | 33 +++++++++++++++++++
.../app/tools/import-export/dialog/index.ts | 1 +
.../import-export/import-export.module.ts | 7 +++-
.../tools/import-export/import.component.ts | 32 +++++-------------
5 files changed, 77 insertions(+), 25 deletions(-)
create mode 100644 apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html
create mode 100644 apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts
diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html
new file mode 100644
index 00000000000..c1ad8b53932
--- /dev/null
+++ b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html
@@ -0,0 +1,29 @@
+
+
+ {{ "importError" | i18n }}
+
+
+
+ {{ "resolveTheErrorsBelowAndTryAgain" | i18n }}
+
+
+
+ | {{ "name" | i18n }} |
+ {{ "description" | i18n }} |
+
+
+
+
+ | {{ r.type }} |
+ {{ r.message }} |
+
+
+
+
+
+
+
+
+
diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts
new file mode 100644
index 00000000000..abb68cf53b1
--- /dev/null
+++ b/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts
@@ -0,0 +1,33 @@
+import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
+import { Component, Inject, OnInit } from "@angular/core";
+
+import { TableDataSource } from "@bitwarden/components";
+
+export interface ErrorListItem {
+ type: string;
+ message: string;
+}
+
+@Component({
+ selector: "app-import-error-dialog",
+ templateUrl: "./import-error-dialog.component.html",
+})
+export class ImportErrorDialogComponent implements OnInit {
+ protected dataSource = new TableDataSource();
+
+ constructor(public dialogRef: DialogRef, @Inject(DIALOG_DATA) public data: Error) {}
+
+ ngOnInit(): void {
+ const split = this.data.message.split("\n\n");
+ if (split.length == 1) {
+ this.dataSource.data = [{ type: "", message: this.data.message }];
+ return;
+ }
+
+ const data: ErrorListItem[] = [];
+ split.forEach((line) => {
+ data.push({ type: "", message: line });
+ });
+ this.dataSource.data = data;
+ }
+}
diff --git a/apps/web/src/app/tools/import-export/dialog/index.ts b/apps/web/src/app/tools/import-export/dialog/index.ts
index 7ad42fe1db9..641cd6600a1 100644
--- a/apps/web/src/app/tools/import-export/dialog/index.ts
+++ b/apps/web/src/app/tools/import-export/dialog/index.ts
@@ -1,2 +1,3 @@
+export * from "./import-error-dialog.component";
export * from "./import-success-dialog.component";
export * from "./file-password-prompt.component";
diff --git a/apps/web/src/app/tools/import-export/import-export.module.ts b/apps/web/src/app/tools/import-export/import-export.module.ts
index 4d59f412367..d180417cdcc 100644
--- a/apps/web/src/app/tools/import-export/import-export.module.ts
+++ b/apps/web/src/app/tools/import-export/import-export.module.ts
@@ -15,7 +15,11 @@ import {
import { LooseComponentsModule, SharedModule } from "../../shared";
-import { ImportSuccessDialogComponent, FilePasswordPromptComponent } from "./dialog";
+import {
+ ImportErrorDialogComponent,
+ ImportSuccessDialogComponent,
+ FilePasswordPromptComponent,
+} from "./dialog";
import { ExportComponent } from "./export.component";
import { ImportExportRoutingModule } from "./import-export-routing.module";
import { ImportComponent } from "./import.component";
@@ -26,6 +30,7 @@ import { ImportComponent } from "./import.component";
ImportComponent,
ExportComponent,
FilePasswordPromptComponent,
+ ImportErrorDialogComponent,
ImportSuccessDialogComponent,
],
providers: [
diff --git a/apps/web/src/app/tools/import-export/import.component.ts b/apps/web/src/app/tools/import-export/import.component.ts
index eb9201f021d..fb7d1d5501d 100644
--- a/apps/web/src/app/tools/import-export/import.component.ts
+++ b/apps/web/src/app/tools/import-export/import.component.ts
@@ -4,7 +4,6 @@ import { Router } from "@angular/router";
import * as JSZip from "jszip";
import { concat, Observable, Subject, lastValueFrom, combineLatest } from "rxjs";
import { map, takeUntil } from "rxjs/operators";
-import Swal, { SweetAlertIcon } from "sweetalert2";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import {
@@ -31,7 +30,11 @@ import {
ImportType,
} from "@bitwarden/importer";
-import { FilePasswordPromptComponent, ImportSuccessDialogComponent } from "./dialog";
+import {
+ FilePasswordPromptComponent,
+ ImportErrorDialogComponent,
+ ImportSuccessDialogComponent,
+} from "./dialog";
@Component({
selector: "app-import",
@@ -247,7 +250,9 @@ export class ImportComponent implements OnInit, OnDestroy {
this.syncService.fullSync(true);
await this.onSuccessfulImport();
} catch (e) {
- this.error(e);
+ this.dialogService.open(ImportErrorDialogComponent, {
+ data: e,
+ });
this.logService.error(e);
}
}
@@ -303,27 +308,6 @@ export class ImportComponent implements OnInit, OnDestroy {
this.fileSelected = fileInputEl.files.length > 0 ? fileInputEl.files[0] : null;
}
- private async error(error: Error) {
- await Swal.fire({
- heightAuto: false,
- buttonsStyling: false,
- icon: "error" as SweetAlertIcon,
- iconHtml: ``,
- input: "textarea",
- inputValue: error.message,
- inputAttributes: {
- readonly: "true",
- },
- titleText: this.i18nService.t("importError"),
- text: this.i18nService.t("importErrorDesc"),
- showConfirmButton: true,
- confirmButtonText: this.i18nService.t("ok"),
- onOpen: (popupEl) => {
- popupEl.querySelector(".swal2-textarea").scrollTo(0, 0);
- },
- });
- }
-
private getFileContents(file: File): Promise {
if (this.format === "1password1pux") {
return this.extractZipContent(file, "export.data");
From f999e2cea96695df8458460a91a88b0dc8f53594 Mon Sep 17 00:00:00 2001
From: Will Martin
Date: Mon, 11 Sep 2023 14:54:23 -0400
Subject: [PATCH 04/25] [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
---
.../background/nativeMessaging.background.ts | 7 +--
apps/browser/src/popup/app.component.ts | 24 +++------
...op-sync-verification-dialog.component.html | 18 +++++++
...ktop-sync-verification-dialog.component.ts | 24 +++++++++
.../await-desktop-dialog.component.html | 11 ++++
.../await-desktop-dialog.component.ts | 17 ++++++
.../src/popup/settings/settings.component.ts | 47 +++++------------
apps/desktop/src/app/app.component.ts | 15 ++----
...er-sync-verification-dialog.component.html | 19 +++++++
...wser-sync-verification-dialog.component.ts | 25 +++++++++
...ify-native-messaging-dialog.component.html | 18 +++++++
...erify-native-messaging-dialog.component.ts | 24 +++++++++
.../src/app/services/services.module.ts | 1 +
.../native-message-handler.service.ts | 26 ++++------
.../src/services/native-messaging.service.ts | 52 +++++++++----------
.../manage/group-add-edit.component.html | 8 +--
.../fingerprint-dialog.component.html | 23 ++++++++
.../fingerprint-dialog.component.ts | 22 ++++++++
libs/auth/src/index.ts | 1 +
.../directives/dialog-close.directive.ts | 4 +-
20 files changed, 268 insertions(+), 118 deletions(-)
create mode 100644 apps/browser/src/popup/components/desktop-sync-verification-dialog.component.html
create mode 100644 apps/browser/src/popup/components/desktop-sync-verification-dialog.component.ts
create mode 100644 apps/browser/src/popup/settings/await-desktop-dialog.component.html
create mode 100644 apps/browser/src/popup/settings/await-desktop-dialog.component.ts
create mode 100644 apps/desktop/src/app/components/browser-sync-verification-dialog.component.html
create mode 100644 apps/desktop/src/app/components/browser-sync-verification-dialog.component.ts
create mode 100644 apps/desktop/src/app/components/verify-native-messaging-dialog.component.html
create mode 100644 apps/desktop/src/app/components/verify-native-messaging-dialog.component.ts
create mode 100644 libs/auth/src/components/fingerprint-dialog.component.html
create mode 100644 libs/auth/src/components/fingerprint-dialog.component.ts
diff --git a/apps/browser/src/background/nativeMessaging.background.ts b/apps/browser/src/background/nativeMessaging.background.ts
index d393022b7b9..88fd81a3a70 100644
--- a/apps/browser/src/background/nativeMessaging.background.ts
+++ b/apps/browser/src/background/nativeMessaging.background.ts
@@ -422,9 +422,10 @@ export class NativeMessagingBackground {
}
private async showFingerprintDialog() {
- const fingerprint = (
- await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey)
- ).join(" ");
+ const fingerprint = await this.cryptoService.getFingerprint(
+ await this.stateService.getUserId(),
+ this.publicKey
+ );
this.messagingService.send("showNativeMessagingFinterprintDialog", {
fingerprint: fingerprint,
diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts
index 815109c5499..4af5b49b52e 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",
@@ -113,10 +113,10 @@ export class AppComponent implements OnInit, OnDestroy {
});
}
} else if (msg.command === "showDialog") {
- await this.showDialog(msg);
+ await this.ngZone.run(() => this.showDialog(msg));
} else if (msg.command === "showNativeMessagingFinterprintDialog") {
// 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") {
this.ngZone.run(() => {
this.showToast(msg);
@@ -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 00000000000..a2a2cd97805
--- /dev/null
+++ b/apps/browser/src/popup/components/desktop-sync-verification-dialog.component.html
@@ -0,0 +1,18 @@
+
+
+ {{ "desktopSyncVerificationTitle" | i18n }}
+
+
+
+ {{ "desktopIntegrationVerificationText" | i18n }}
+
+
+ {{ params.fingerprint.join("-") }}
+
+
+
+
+
+
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 00000000000..c860ef1e342
--- /dev/null
+++ b/apps/browser/src/popup/components/desktop-sync-verification-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 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,
+ });
+ }
+}
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 00000000000..688071a15d6
--- /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 00000000000..9ed6efe036f
--- /dev/null
+++ b/apps/browser/src/popup/settings/await-desktop-dialog.component.ts
@@ -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(AwaitDesktopDialogComponent, {
+ disableClose: true,
+ });
+ }
+}
diff --git a/apps/browser/src/popup/settings/settings.component.ts b/apps/browser/src/popup/settings/settings.component.ts
index 30a1f03eacf..efeb6aba6d2 100644
--- a/apps/browser/src/popup/settings/settings.component.ts
+++ b/apps/browser/src/popup/settings/settings.component.ts
@@ -15,9 +15,9 @@ import {
switchMap,
takeUntil,
} from "rxjs";
-import Swal from "sweetalert2";
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 { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
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 { AboutComponent } from "./about.component";
+import { AwaitDesktopDialogComponent } from "./await-desktop-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);
}
@@ -388,8 +379,6 @@ export class SettingsComponent implements OnInit {
.authenticateBiometric()
.then((result) => {
this.form.controls.biometric.setValue(result);
-
- Swal.close();
if (!result) {
this.platformUtilsService.showToast(
"error",
@@ -411,6 +400,9 @@ export class SettingsComponent implements OnInit {
cancelButtonText: null,
type: "danger",
});
+ })
+ .finally(() => {
+ awaitDesktopDialogRef.close(false);
}),
]);
} else {
@@ -497,27 +489,12 @@ export class SettingsComponent implements OnInit {
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 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/app.component.ts b/apps/desktop/src/app/app.component.ts
index 39e2d2f8b11..34262c3a309 100644
--- a/apps/desktop/src/app/app.component.ts
+++ b/apps/desktop/src/app/app.component.ts
@@ -16,6 +16,7 @@ import { firstValueFrom, Subject, takeUntil } from "rxjs";
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
import { ModalService } from "@bitwarden/angular/services/modal.service";
+import { FingerprintDialogComponent } from "@bitwarden/auth";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.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(
await this.stateService.getUserId()
);
- const result = await this.dialogService.openSimpleDialog({
- title: { key: "fingerprintPhrase" },
- 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/");
- }
+ const dialogRef = FingerprintDialogComponent.open(this.dialogService, { fingerprint });
+ await firstValueFrom(dialogRef.closed);
break;
}
case "deleteAccount":
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 00000000000..63bffe9c4e0
--- /dev/null
+++ b/apps/desktop/src/app/components/browser-sync-verification-dialog.component.html
@@ -0,0 +1,19 @@
+
+
+ {{ "verifyBrowserTitle" | i18n }}
+
+
+ {{ "verifyBrowserDesc" | i18n }}
+
+ {{ params.fingerprint.join("-") }}
+
+
+
+
+
+
+
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 00000000000..aefa5672a94
--- /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 00000000000..0334857962b
--- /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 00000000000..507d566336b
--- /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/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts
index 42208077c33..87fb1eecfcb 100644
--- a/apps/desktop/src/app/services/services.module.ts
+++ b/apps/desktop/src/app/services/services.module.ts
@@ -169,6 +169,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
MessagingServiceAbstraction,
I18nServiceAbstraction,
EncryptedMessageHandlerService,
+ DialogService,
],
},
{
diff --git a/apps/desktop/src/services/native-message-handler.service.ts b/apps/desktop/src/services/native-message-handler.service.ts
index 9f5f1d460df..6779195c3f1 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 nativeMessagingVerified = await firstValueFrom(
+ VerifyNativeMessagingDialogComponent.open(this.dialogService, { applicationName }).closed
+ );
+
+ if (nativeMessagingVerified !== 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 3928778f313..c18a67e6b43 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 { Injectable, NgZone } 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,9 @@ export class NativeMessagingService {
private i18nService: I18nService,
private messagingService: MessagingService,
private stateService: StateService,
- private nativeMessageHandler: NativeMessageHandlerService
+ private nativeMessageHandler: NativeMessageHandlerService,
+ private dialogService: DialogService,
+ private ngZone: NgZone
) {}
init() {
@@ -69,27 +72,20 @@ export class NativeMessagingService {
if (await this.stateService.getEnableBrowserIntegrationFingerprint()) {
ipcRenderer.send("nativeMessagingReply", { command: "verifyFingerprint", appId: appId });
- const fingerprint = (
- await this.cryptoService.getFingerprint(
- await this.stateService.getUserId(),
- remotePublicKey
- )
- ).join(" ");
+ const fingerprint = await this.cryptoService.getFingerprint(
+ await this.stateService.getUserId(),
+ remotePublicKey
+ );
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 dialogRef = this.ngZone.run(() =>
+ BrowserSyncVerificationDialogComponent.open(this.dialogService, { fingerprint })
+ );
- if (submitted.value !== true) {
+ const browserSyncVerified = await firstValueFrom(dialogRef.closed);
+
+ if (browserSyncVerified !== true) {
return;
}
}
@@ -127,13 +123,15 @@ 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.ngZone.run(() =>
+ this.dialogService.openSimpleDialog({
+ type: "warning",
+ title: { key: "biometricsNotEnabledTitle" },
+ content: { key: "biometricsNotEnabledDesc" },
+ cancelButtonText: null,
+ acceptButtonText: { key: "cancel" },
+ })
+ );
}
const userKey = await this.cryptoService.getUserKeyFromStorage(
diff --git a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html
index 4978842fb4d..b6175d80297 100644
--- a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html
+++ b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html
@@ -69,13 +69,7 @@
-