From 4555e95323ad2842b46d3b24def2248546cb9419 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 13 Jan 2025 17:06:57 +0100 Subject: [PATCH] Fix biometrics not working in firefox or windows --- .../settings/account-security.component.ts | 11 +++++- .../browser/src/background/main.background.ts | 12 ++++--- .../background/nativeMessaging.background.ts | 4 +++ .../background-browser-biometrics.service.ts | 36 +++++++++++++++++-- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index 3b1727f89ac..1a64d860e45 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -507,7 +507,16 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { const biometricsPromise = async () => { try { - const result = await this.biometricsService.authenticateWithBiometrics(); + const userId = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a.id)), + ); + let result = false; + try { + const userKey = await this.biometricsService.unlockWithBiometricsForUser(userId); + result = await this.keyService.validateUserKey(userKey, userId); + } catch (e) { + result = false; + } // prevent duplicate dialog biometricsResponseReceived = true; diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 4bec3d6cc0a..98f3867e5ff 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -632,11 +632,6 @@ export default class MainBackground { this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider); - this.biometricsService = new BackgroundBrowserBiometricsService( - runtimeNativeMessagingBackground, - this.logService, - ); - this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider); this.pinService = new PinService( @@ -665,6 +660,13 @@ export default class MainBackground { this.kdfConfigService, ); + this.biometricsService = new BackgroundBrowserBiometricsService( + runtimeNativeMessagingBackground, + this.logService, + this.keyService, + this.biometricStateService, + ); + this.appIdService = new AppIdService(this.storageService, this.logService); this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); diff --git a/apps/browser/src/background/nativeMessaging.background.ts b/apps/browser/src/background/nativeMessaging.background.ts index 116d048d2e8..630e071f64a 100644 --- a/apps/browser/src/background/nativeMessaging.background.ts +++ b/apps/browser/src/background/nativeMessaging.background.ts @@ -281,6 +281,7 @@ export class NativeMessagingBackground { }); message.messageId = messageId; try { + this.logService.info("DEBUG: Sending message of type " + message.command); await this.send(message); } catch (e) { this.logService.info( @@ -374,6 +375,8 @@ export class NativeMessagingBackground { return; } + this.logService.info("DEBUG:recv message", message); + const messageId = message.messageId; if ( @@ -391,6 +394,7 @@ export class NativeMessagingBackground { } if (this.callbacks.has(messageId)) { + this.logService.info("[Native Messaging IPC] Received message with a callback", message); this.callbacks.get(messageId).resolver(message); } else { this.logService.info("[Native Messaging IPC] Received message without a callback", message); diff --git a/apps/browser/src/key-management/biometrics/background-browser-biometrics.service.ts b/apps/browser/src/key-management/biometrics/background-browser-biometrics.service.ts index 8e6fc562d14..4ef3bfc5c4f 100644 --- a/apps/browser/src/key-management/biometrics/background-browser-biometrics.service.ts +++ b/apps/browser/src/key-management/biometrics/background-browser-biometrics.service.ts @@ -1,9 +1,17 @@ import { Injectable } from "@angular/core"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; -import { BiometricsService, BiometricsCommands, BiometricsStatus } from "@bitwarden/key-management"; +import { + BiometricsService, + BiometricsCommands, + BiometricsStatus, + KeyService, + BiometricStateService, +} from "@bitwarden/key-management"; import { NativeMessagingBackground } from "../../background/nativeMessaging.background"; import { BrowserApi } from "../../platform/browser/browser-api"; @@ -13,6 +21,8 @@ export class BackgroundBrowserBiometricsService extends BiometricsService { constructor( private nativeMessagingBackground: () => NativeMessagingBackground, private logService: LogService, + private keyService: KeyService, + private biometricStateService: BiometricStateService, ) { super(); } @@ -75,21 +85,41 @@ export class BackgroundBrowserBiometricsService extends BiometricsService { await this.ensureConnected(); if (this.nativeMessagingBackground().isConnectedToOutdatedDesktopClient) { + this.logService.info("Biometric unlock for user outdated", userId); const response = await this.nativeMessagingBackground().callCommand({ command: BiometricsCommands.Unlock, }); + this.logService.info("Biometric unlock for user", response); if (response.response == "unlocked") { - return response.userKeyB64; + const decodedUserkey = Utils.fromB64ToArray(response.userKeyB64); + const userKey = new SymmetricCryptoKey(decodedUserkey) as UserKey; + if (this.keyService.validateUserKey(userKey, userId)) { + this.logService.info("validated setting enabled"); + await this.biometricStateService.setBiometricUnlockEnabled(true); + await this.biometricStateService.setFingerprintValidated(true); + this.keyService.setUserKey(userKey, userId); + return userKey; + } } else { return null; } } else { + this.logService.info("Unlock for new user", userId); const response = await this.nativeMessagingBackground().callCommand({ command: BiometricsCommands.UnlockWithBiometricsForUser, userId: userId, }); + this.logService.info("Biometric unlock for user1", response); if (response.response) { - return response.userKeyB64; + const decodedUserkey = Utils.fromB64ToArray(response.userKeyB64); + const userKey = new SymmetricCryptoKey(decodedUserkey) as UserKey; + if (this.keyService.validateUserKey(userKey, userId)) { + this.logService.info("validated setting enabled"); + await this.biometricStateService.setBiometricUnlockEnabled(true); + await this.biometricStateService.setFingerprintValidated(true); + this.keyService.setUserKey(userKey, userId); + return userKey; + } } else { return null; }