mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 00:33:44 +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:
@@ -507,7 +507,16 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
const biometricsPromise = async () => {
|
const biometricsPromise = async () => {
|
||||||
try {
|
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
|
// prevent duplicate dialog
|
||||||
biometricsResponseReceived = true;
|
biometricsResponseReceived = true;
|
||||||
|
|||||||
@@ -632,11 +632,6 @@ export default class MainBackground {
|
|||||||
|
|
||||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);
|
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);
|
||||||
|
|
||||||
this.biometricsService = new BackgroundBrowserBiometricsService(
|
|
||||||
runtimeNativeMessagingBackground,
|
|
||||||
this.logService,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider);
|
this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider);
|
||||||
|
|
||||||
this.pinService = new PinService(
|
this.pinService = new PinService(
|
||||||
@@ -665,6 +660,13 @@ export default class MainBackground {
|
|||||||
this.kdfConfigService,
|
this.kdfConfigService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.biometricsService = new BackgroundBrowserBiometricsService(
|
||||||
|
runtimeNativeMessagingBackground,
|
||||||
|
this.logService,
|
||||||
|
this.keyService,
|
||||||
|
this.biometricStateService,
|
||||||
|
);
|
||||||
|
|
||||||
this.appIdService = new AppIdService(this.storageService, this.logService);
|
this.appIdService = new AppIdService(this.storageService, this.logService);
|
||||||
|
|
||||||
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
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 { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
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 { NativeMessagingBackground } from "../../background/nativeMessaging.background";
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
@@ -13,6 +21,8 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
|
|||||||
constructor(
|
constructor(
|
||||||
private nativeMessagingBackground: () => NativeMessagingBackground,
|
private nativeMessagingBackground: () => NativeMessagingBackground,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
|
private keyService: KeyService,
|
||||||
|
private biometricStateService: BiometricStateService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -74,12 +84,20 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
|
|||||||
try {
|
try {
|
||||||
await this.ensureConnected();
|
await this.ensureConnected();
|
||||||
|
|
||||||
|
// todo remove after 2025.3
|
||||||
if (this.nativeMessagingBackground().isConnectedToOutdatedDesktopClient) {
|
if (this.nativeMessagingBackground().isConnectedToOutdatedDesktopClient) {
|
||||||
const response = await this.nativeMessagingBackground().callCommand({
|
const response = await this.nativeMessagingBackground().callCommand({
|
||||||
command: BiometricsCommands.Unlock,
|
command: BiometricsCommands.Unlock,
|
||||||
});
|
});
|
||||||
if (response.response == "unlocked") {
|
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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -89,7 +107,15 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
|
|||||||
userId: userId,
|
userId: userId,
|
||||||
});
|
});
|
||||||
if (response.response) {
|
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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -98,6 +124,8 @@ export class BackgroundBrowserBiometricsService extends BiometricsService {
|
|||||||
this.logService.info("Biometric unlock for user failed", e);
|
this.logService.info("Biometric unlock for user failed", e);
|
||||||
throw new Error("Biometric unlock failed");
|
throw new Error("Biometric unlock failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
import { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
|
import { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
|
||||||
@@ -29,13 +28,13 @@ export class ForegroundBrowserBiometricsService extends BiometricsService {
|
|||||||
|
|
||||||
async unlockWithBiometricsForUser(userId: UserId): Promise<UserKey | null> {
|
async unlockWithBiometricsForUser(userId: UserId): Promise<UserKey | null> {
|
||||||
const response = await BrowserApi.sendMessageWithResponse<{
|
const response = await BrowserApi.sendMessageWithResponse<{
|
||||||
result: string;
|
result: UserKey;
|
||||||
error: string;
|
error: string;
|
||||||
}>(BiometricsCommands.UnlockWithBiometricsForUser, { userId });
|
}>(BiometricsCommands.UnlockWithBiometricsForUser, { userId });
|
||||||
if (!response.result) {
|
if (!response.result) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return SymmetricCryptoKey.fromString(response.result) as UserKey;
|
return response.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
||||||
|
|||||||
Reference in New Issue
Block a user