mirror of
https://github.com/bitwarden/browser
synced 2026-01-21 03:43:41 +00:00
[PM-6296] Fix biometrics error prompt when biometrics are temporarily unavailable in browser extension (v2) (#10374)
* Create unavailable message for biometrics when in clamshell mode * Move browser biometrics * Inject nativemessagingbackground instead of using constructor * Fix linting * Fix build on browser
This commit is contained in:
@@ -3,7 +3,7 @@ import { systemPreferences } from "electron";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { passwords } from "@bitwarden/desktop-napi";
|
||||
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
export default class BiometricDarwinMain implements OsBiometricService {
|
||||
constructor(private i18nservice: I18nService) {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
export default class NoopBiometricsService implements OsBiometricService {
|
||||
constructor() {}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { biometrics, passwords } from "@bitwarden/desktop-napi";
|
||||
import { WindowMain } from "../../../main/window.main";
|
||||
import { isFlatpak, isLinux, isSnapStore } from "../../../utils";
|
||||
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
const polkitPolicy = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC
|
||||
|
||||
@@ -6,7 +6,7 @@ import { biometrics, passwords } from "@bitwarden/desktop-napi";
|
||||
|
||||
import { WindowMain } from "../../../main/window.main";
|
||||
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
const KEY_WITNESS_SUFFIX = "_witness";
|
||||
const WITNESS_VALUE = "known key";
|
||||
|
||||
@@ -11,7 +11,7 @@ import { WindowMain } from "../../../main/window.main";
|
||||
import BiometricDarwinMain from "./biometric.darwin.main";
|
||||
import BiometricWindowsMain from "./biometric.windows.main";
|
||||
import { BiometricsService } from "./biometrics.service";
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
jest.mock("@bitwarden/desktop-napi", () => {
|
||||
return {
|
||||
|
||||
@@ -6,9 +6,9 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { WindowMain } from "../../../main/window.main";
|
||||
|
||||
import { BiometricsServiceAbstraction, OsBiometricService } from "./biometrics.service.abstraction";
|
||||
import { DesktopBiometricsService, OsBiometricService } from "./desktop.biometrics.service";
|
||||
|
||||
export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
export class BiometricsService extends DesktopBiometricsService {
|
||||
private platformSpecificService: OsBiometricService;
|
||||
private clientKeyHalves = new Map<string, string>();
|
||||
|
||||
@@ -20,6 +20,7 @@ export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
private platform: NodeJS.Platform,
|
||||
private biometricStateService: BiometricStateService,
|
||||
) {
|
||||
super();
|
||||
this.loadPlatformSpecificService(this.platform);
|
||||
}
|
||||
|
||||
@@ -63,19 +64,19 @@ export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
this.platformSpecificService = new NoopBiometricsService();
|
||||
}
|
||||
|
||||
async osSupportsBiometric() {
|
||||
async supportsBiometric() {
|
||||
return await this.platformSpecificService.osSupportsBiometric();
|
||||
}
|
||||
|
||||
async osBiometricsNeedsSetup() {
|
||||
async biometricsNeedsSetup() {
|
||||
return await this.platformSpecificService.osBiometricsNeedsSetup();
|
||||
}
|
||||
|
||||
async osBiometricsCanAutoSetup() {
|
||||
async biometricsSupportsAutoSetup() {
|
||||
return await this.platformSpecificService.osBiometricsCanAutoSetup();
|
||||
}
|
||||
|
||||
async osBiometricsSetup() {
|
||||
async biometricsSetup() {
|
||||
await this.platformSpecificService.osBiometricsSetup();
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId);
|
||||
const clientKeyHalfB64 = this.getClientKeyHalf(service, key);
|
||||
const clientKeyHalfSatisfied = !requireClientKeyHalf || !!clientKeyHalfB64;
|
||||
return clientKeyHalfSatisfied && (await this.osSupportsBiometric());
|
||||
return clientKeyHalfSatisfied && (await this.supportsBiometric());
|
||||
}
|
||||
|
||||
async authenticateBiometric(): Promise<boolean> {
|
||||
@@ -110,6 +111,10 @@ export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
return result;
|
||||
}
|
||||
|
||||
async isBiometricUnlockAvailable(): Promise<boolean> {
|
||||
return await this.platformSpecificService.osSupportsBiometric();
|
||||
}
|
||||
|
||||
async getBiometricKey(service: string, storageKey: string): Promise<string | null> {
|
||||
return await this.interruptProcessReload(async () => {
|
||||
await this.enforceClientKeyHalf(service, storageKey);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
export abstract class BiometricsServiceAbstraction {
|
||||
abstract osSupportsBiometric(): Promise<boolean>;
|
||||
abstract osBiometricsNeedsSetup: () => Promise<boolean>;
|
||||
abstract osBiometricsCanAutoSetup: () => Promise<boolean>;
|
||||
abstract osBiometricsSetup: () => Promise<void>;
|
||||
import { BiometricsService } from "@bitwarden/common/platform/biometrics/biometric.service";
|
||||
|
||||
/**
|
||||
* This service extends the base biometrics service to provide desktop specific functions,
|
||||
* specifically for the main process.
|
||||
*/
|
||||
export abstract class DesktopBiometricsService extends BiometricsService {
|
||||
abstract canAuthBiometric({
|
||||
service,
|
||||
key,
|
||||
@@ -12,7 +14,6 @@ export abstract class BiometricsServiceAbstraction {
|
||||
key: string;
|
||||
userId: string;
|
||||
}): Promise<boolean>;
|
||||
abstract authenticateBiometric(): Promise<boolean>;
|
||||
abstract getBiometricKey(service: string, key: string): Promise<string | null>;
|
||||
abstract setBiometricKey(service: string, key: string, value: string): Promise<void>;
|
||||
abstract setEncryptionKeyHalf({
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./biometrics.service.abstraction";
|
||||
export * from "./desktop.biometrics.service";
|
||||
export * from "./biometrics.service";
|
||||
|
||||
@@ -6,14 +6,14 @@ import { passwords } from "@bitwarden/desktop-napi";
|
||||
|
||||
import { BiometricMessage, BiometricAction } from "../../types/biometric-message";
|
||||
|
||||
import { BiometricsServiceAbstraction } from "./biometric/index";
|
||||
import { DesktopBiometricsService } from "./biometric/index";
|
||||
|
||||
const AuthRequiredSuffix = "_biometric";
|
||||
|
||||
export class DesktopCredentialStorageListener {
|
||||
constructor(
|
||||
private serviceName: string,
|
||||
private biometricService: BiometricsServiceAbstraction,
|
||||
private biometricService: DesktopBiometricsService,
|
||||
private logService: ConsoleLogService,
|
||||
) {}
|
||||
|
||||
@@ -77,16 +77,16 @@ export class DesktopCredentialStorageListener {
|
||||
});
|
||||
break;
|
||||
case BiometricAction.OsSupported:
|
||||
val = await this.biometricService.osSupportsBiometric();
|
||||
val = await this.biometricService.supportsBiometric();
|
||||
break;
|
||||
case BiometricAction.NeedsSetup:
|
||||
val = await this.biometricService.osBiometricsNeedsSetup();
|
||||
val = await this.biometricService.biometricsNeedsSetup();
|
||||
break;
|
||||
case BiometricAction.Setup:
|
||||
await this.biometricService.osBiometricsSetup();
|
||||
await this.biometricService.biometricsSetup();
|
||||
break;
|
||||
case BiometricAction.CanAutoSetup:
|
||||
val = await this.biometricService.osBiometricsCanAutoSetup();
|
||||
val = await this.biometricService.biometricsSupportsAutoSetup();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { BiometricsService } from "@bitwarden/common/platform/biometrics/biometric.service";
|
||||
|
||||
/**
|
||||
* This service implement the base biometrics service to provide desktop specific functions,
|
||||
* specifically for the renderer process by passing messages to the main process.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ElectronBiometricsService extends BiometricsService {
|
||||
async supportsBiometric(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.osSupported();
|
||||
}
|
||||
|
||||
async isBiometricUnlockAvailable(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.osSupported();
|
||||
}
|
||||
|
||||
/** This method is used to authenticate the user presence _only_.
|
||||
* It should not be used in the process to retrieve
|
||||
* biometric keys, which has a separate authentication mechanism.
|
||||
* For biometric keys, invoke "keytar" with a biometric key suffix */
|
||||
async authenticateBiometric(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.authenticate();
|
||||
}
|
||||
|
||||
async biometricsNeedsSetup(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.biometricsNeedsSetup();
|
||||
}
|
||||
|
||||
async biometricsSupportsAutoSetup(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.biometricsCanAutoSetup();
|
||||
}
|
||||
|
||||
async biometricsSetup(): Promise<void> {
|
||||
return await ipc.platform.biometric.biometricsSetup();
|
||||
}
|
||||
}
|
||||
@@ -131,30 +131,6 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
|
||||
return ipc.platform.clipboard.read();
|
||||
}
|
||||
|
||||
async supportsBiometric(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.osSupported();
|
||||
}
|
||||
|
||||
async biometricsNeedsSetup(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.biometricsNeedsSetup();
|
||||
}
|
||||
|
||||
async biometricsSupportsAutoSetup(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.biometricsCanAutoSetup();
|
||||
}
|
||||
|
||||
async biometricsSetup(): Promise<void> {
|
||||
return await ipc.platform.biometric.biometricsSetup();
|
||||
}
|
||||
|
||||
/** This method is used to authenticate the user presence _only_.
|
||||
* It should not be used in the process to retrieve
|
||||
* biometric keys, which has a separate authentication mechanism.
|
||||
* For biometric keys, invoke "keytar" with a biometric key suffix */
|
||||
async authenticateBiometric(): Promise<boolean> {
|
||||
return await ipc.platform.biometric.authenticate();
|
||||
}
|
||||
|
||||
supportsSecureStorage(): boolean {
|
||||
return ELECTRON_SUPPORTS_SECURE_STORAGE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user