1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[PM-16985] Fix biometrics not working in firefox or windows (#12833)

* Fix biometrics not working in firefox or windows

* Remove logs

* Update badge after biometric unlock

* Add removal todo note

* Remove debug logging

* Fix type warnings

* Fix userkey typing in background biometrics service

* Simplify types for userkey in foreground-browser-biometrics and runtime.background.ts
This commit is contained in:
Bernd Schoolmann
2025-01-14 16:20:18 +01:00
committed by GitHub
parent fbb1211a7b
commit 8e95029439
4 changed files with 50 additions and 12 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
}
@@ -74,12 +84,20 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
try {
await this.ensureConnected();
// todo remove after 2025.3
if (this.nativeMessagingBackground().isConnectedToOutdatedDesktopClient) {
const response = await this.nativeMessagingBackground().callCommand({
command: BiometricsCommands.Unlock,
});
if (response.response == "unlocked") {
return response.userKeyB64;
const decodedUserkey = Utils.fromB64ToArray(response.userKeyB64);
const userKey = new SymmetricCryptoKey(decodedUserkey) as UserKey;
if (await this.keyService.validateUserKey(userKey, userId)) {
await this.biometricStateService.setBiometricUnlockEnabled(true);
await this.biometricStateService.setFingerprintValidated(true);
this.keyService.setUserKey(userKey, userId);
return userKey;
}
} else {
return null;
}
@@ -89,7 +107,15 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
userId: userId,
});
if (response.response) {
return response.userKeyB64;
// In case the requesting foreground context dies (popup), the userkey should still be set, so the user is unlocked / the setting should be enabled
const decodedUserkey = Utils.fromB64ToArray(response.userKeyB64);
const userKey = new SymmetricCryptoKey(decodedUserkey) as UserKey;
if (await this.keyService.validateUserKey(userKey, userId)) {
await this.biometricStateService.setBiometricUnlockEnabled(true);
await this.biometricStateService.setFingerprintValidated(true);
this.keyService.setUserKey(userKey, userId);
return userKey;
}
} else {
return null;
}
@@ -98,6 +124,8 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
this.logService.info("Biometric unlock for user failed", e);
throw new Error("Biometric unlock failed");
}
return null;
}
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {

View File

@@ -1,4 +1,3 @@
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 { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
@@ -29,13 +28,13 @@ export class ForegroundBrowserBiometricsService extends BiometricsService {
async unlockWithBiometricsForUser(userId: UserId): Promise<UserKey | null> {
const response = await BrowserApi.sendMessageWithResponse<{
result: string;
result: UserKey;
error: string;
}>(BiometricsCommands.UnlockWithBiometricsForUser, { userId });
if (!response.result) {
return null;
}
return SymmetricCryptoKey.fromString(response.result) as UserKey;
return response.result;
}
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {