From d5334360dd1c9af4e3a7e96f28e6d1cbd93906cc Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 15 Mar 2022 13:13:39 +0100 Subject: [PATCH] Add support for no intrusive biometric (#2431) --- src/_locales/en/messages.json | 5 ++- src/background/nativeMessaging.background.ts | 20 +++--------- src/models/biometricErrors.ts | 17 +++++++++++ src/popup/accounts/lock.component.html | 12 +++++++- src/popup/accounts/lock.component.ts | 32 +++++++++++--------- src/popup/app.component.ts | 2 +- src/popup/scss/plugins.scss | 2 +- src/popup/settings/settings.component.ts | 13 +++++++- webpack.config.js | 4 +++ 9 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 src/models/biometricErrors.ts diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 276b045a9b..19daa712f7 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1494,7 +1494,7 @@ "message": "Start the Bitwarden Desktop application" }, "startDesktopDesc": { - "message": "The Bitwarden Desktop application needs to be started before this function can be used." + "message": "The Bitwarden Desktop application needs to be started before unlock with biometrics can be used." }, "errorEnableBiometricTitle": { "message": "Unable to enable biometrics" @@ -1884,5 +1884,8 @@ "example": "name@example.com" } } + }, + "error": { + "message": "Error" } } diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index 49a465cf0e..eb03d805c1 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -115,13 +115,7 @@ export class NativeMessagingBackground { break; case "disconnected": if (this.connecting) { - this.messagingService.send("showDialog", { - text: this.i18nService.t("startDesktopDesc"), - title: this.i18nService.t("startDesktopTitle"), - confirmText: this.i18nService.t("ok"), - type: "error", - }); - reject(); + reject("startDesktop"); } this.connected = false; this.port.disconnect(); @@ -192,18 +186,12 @@ export class NativeMessagingBackground { error = chrome.runtime.lastError.message; } - if (error != null) { - this.messagingService.send("showDialog", { - text: this.i18nService.t("desktopIntegrationDisabledDesc"), - title: this.i18nService.t("desktopIntegrationDisabledTitle"), - confirmText: this.i18nService.t("ok"), - type: "error", - }); - } this.sharedSecret = null; this.privateKey = null; this.connected = false; - reject(); + + const reason = error != null ? "desktopIntegrationDisabled" : null; + reject(reason); }); }); } diff --git a/src/models/biometricErrors.ts b/src/models/biometricErrors.ts new file mode 100644 index 0000000000..822a5c16f4 --- /dev/null +++ b/src/models/biometricErrors.ts @@ -0,0 +1,17 @@ +type BiometricError = { + title: string; + description: string; +}; + +export type BiometricErrorTypes = "startDesktop" | "desktopIntegrationDisabled"; + +export const BiometricErrors: Record = { + startDesktop: { + title: "startDesktopTitle", + description: "startDesktopDesc", + }, + desktopIntegrationDisabled: { + title: "desktopIntegrationDisabledTitle", + description: "desktopIntegrationDisabledDesc", + }, +}; diff --git a/src/popup/accounts/lock.component.html b/src/popup/accounts/lock.component.html index 68edd697a4..efc11dcf41 100644 --- a/src/popup/accounts/lock.component.html +++ b/src/popup/accounts/lock.component.html @@ -62,7 +62,13 @@
@@ -71,5 +77,9 @@

+ {{ biometricError }} +

+ {{ "awaitDesktop" | i18n }} +

diff --git a/src/popup/accounts/lock.component.ts b/src/popup/accounts/lock.component.ts index 8047a683dc..52f0f9b1d9 100644 --- a/src/popup/accounts/lock.component.ts +++ b/src/popup/accounts/lock.component.ts @@ -1,6 +1,5 @@ import { Component, NgZone } from "@angular/core"; import { Router } from "@angular/router"; -import Swal from "sweetalert2"; import { LockComponent as BaseLockComponent } from "jslib-angular/components/lock.component"; import { ApiService } from "jslib-common/abstractions/api.service"; @@ -14,6 +13,8 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se import { StateService } from "jslib-common/abstractions/state.service"; import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; +import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors"; + @Component({ selector: "app-lock", templateUrl: "lock.component.html", @@ -21,6 +22,9 @@ import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.serv export class LockComponent extends BaseLockComponent { private isInitialLockScreen: boolean; + biometricError: string; + pendingBiometric = false; + constructor( router: Router, i18nService: I18nService, @@ -73,24 +77,22 @@ export class LockComponent extends BaseLockComponent { return; } - const div = document.createElement("div"); - div.innerHTML = `
${this.i18nService.t("awaitDesktop")}
`; + this.pendingBiometric = true; + this.biometricError = null; - Swal.fire({ - heightAuto: false, - buttonsStyling: false, - html: div, - showCancelButton: true, - cancelButtonText: this.i18nService.t("cancel"), - showConfirmButton: false, - }); + let success; + try { + success = await super.unlockBiometric(); + } catch (e) { + const error = BiometricErrors[e as BiometricErrorTypes]; - const success = await super.unlockBiometric(); + if (error == null) { + this.logService.error("Unknown error: " + e); + } - // Avoid closing the error dialogs - if (success) { - Swal.close(); + this.biometricError = this.i18nService.t(error.description); } + this.pendingBiometric = false; return success; } diff --git a/src/popup/app.component.ts b/src/popup/app.component.ts index 1900749f60..771c696be3 100644 --- a/src/popup/app.component.ts +++ b/src/popup/app.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, NgZone, OnInit, SecurityContext } from "@ import { DomSanitizer } from "@angular/platform-browser"; import { NavigationEnd, Router, RouterOutlet } from "@angular/router"; import { IndividualConfig, ToastrService } from "ngx-toastr"; -import Swal, { SweetAlertIcon } from "sweetalert2/src/sweetalert2.js"; +import Swal, { SweetAlertIcon } from "sweetalert2"; import { AuthService } from "jslib-common/abstractions/auth.service"; import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service"; diff --git a/src/popup/scss/plugins.scss b/src/popup/scss/plugins.scss index b75bf109b4..44a181c0dc 100644 --- a/src/popup/scss/plugins.scss +++ b/src/popup/scss/plugins.scss @@ -1,5 +1,5 @@ @import "~ngx-toastr/toastr"; -@import "~sweetalert2/src/sweetalert2.scss"; +@import "~#sweetalert2"; @import "variables.scss"; @import "buttons.scss"; diff --git a/src/popup/settings/settings.component.ts b/src/popup/settings/settings.component.ts index aab4885a09..a616b39a41 100644 --- a/src/popup/settings/settings.component.ts +++ b/src/popup/settings/settings.component.ts @@ -1,7 +1,7 @@ import { Component, ElementRef, OnInit, ViewChild } from "@angular/core"; import { FormControl } from "@angular/forms"; import { Router } from "@angular/router"; -import Swal from "sweetalert2/src/sweetalert2.js"; +import Swal from "sweetalert2"; import { ModalService } from "jslib-angular/services/modal.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service"; @@ -15,6 +15,7 @@ import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.serv import { DeviceType } from "jslib-common/enums/deviceType"; import { BrowserApi } from "../../browser/browserApi"; +import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors"; import { SetPinComponent } from "../components/set-pin.component"; import { PopupUtilsService } from "../services/popup-utils.service"; @@ -269,6 +270,16 @@ export class SettingsComponent implements OnInit { .catch((e) => { // Handle connection errors this.biometric = false; + + const error = BiometricErrors[e as BiometricErrorTypes]; + + this.platformUtilsService.showDialog( + this.i18nService.t(error.description), + this.i18nService.t(error.title), + this.i18nService.t("ok"), + null, + "error" + ); }), ]); } else { diff --git a/webpack.config.js b/webpack.config.js index 0d8b894206..6714427680 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -168,6 +168,10 @@ const config = { extensions: [".ts", ".js"], symlinks: false, modules: [path.resolve("node_modules")], + alias: { + sweetalert2: require.resolve("sweetalert2/dist/sweetalert2.js"), + "#sweetalert2": require.resolve("sweetalert2/src/sweetalert2.scss"), + }, fallback: { assert: false, buffer: require.resolve("buffer/"),