mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 13:10:17 +00:00
Refactor biometrics service
Create BiometricsService that takes care of loading the platformspecifc services, hiding the implementation details Make it clearer which dependencies are needed by a specific biometrics-service (compile-error vs runtime-error) Add unit tests Isolate biometrics import/exports with a barrel file
This commit is contained in:
@@ -7,7 +7,7 @@ import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
||||
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
|
||||
import { StateService } from "@bitwarden/common/services/state.service";
|
||||
|
||||
import { BiometricMain } from "./main/biometric/biometric.main";
|
||||
import { BiometricsService, BiometricsServiceAbstraction } from "./main/biometric/index";
|
||||
import { DesktopCredentialStorageListener } from "./main/desktop-credential-storage-listener";
|
||||
import { MenuMain } from "./main/menu/menu.main";
|
||||
import { MessagingMain } from "./main/messaging.main";
|
||||
@@ -37,7 +37,7 @@ export class Main {
|
||||
menuMain: MenuMain;
|
||||
powerMonitorMain: PowerMonitorMain;
|
||||
trayMain: TrayMain;
|
||||
biometricMain: BiometricMain;
|
||||
biometricsService: BiometricsServiceAbstraction;
|
||||
nativeMessagingMain: NativeMessagingMain;
|
||||
|
||||
constructor() {
|
||||
@@ -117,24 +117,16 @@ export class Main {
|
||||
this.updaterMain
|
||||
);
|
||||
|
||||
if (process.platform === "win32") {
|
||||
// eslint-disable-next-line
|
||||
const BiometricWindowsMain = require("./main/biometric/biometric.windows.main").default;
|
||||
this.biometricMain = new BiometricWindowsMain(
|
||||
this.i18nService,
|
||||
this.windowMain,
|
||||
this.stateService,
|
||||
this.logService
|
||||
);
|
||||
} else if (process.platform === "darwin") {
|
||||
// eslint-disable-next-line
|
||||
const BiometricDarwinMain = require("./main/biometric/biometric.darwin.main").default;
|
||||
this.biometricMain = new BiometricDarwinMain(this.i18nService, this.stateService);
|
||||
}
|
||||
this.biometricsService = new BiometricsService(
|
||||
this.i18nService,
|
||||
this.windowMain,
|
||||
this.stateService,
|
||||
this.logService
|
||||
);
|
||||
|
||||
this.desktopCredentialStorageListener = new DesktopCredentialStorageListener(
|
||||
"Bitwarden",
|
||||
this.biometricMain
|
||||
this.biometricsService
|
||||
);
|
||||
|
||||
this.nativeMessagingMain = new NativeMessagingMain(
|
||||
@@ -166,8 +158,8 @@ export class Main {
|
||||
}
|
||||
this.powerMonitorMain.init();
|
||||
await this.updaterMain.init();
|
||||
if (this.biometricMain != null) {
|
||||
await this.biometricMain.init();
|
||||
if (this.biometricsService != null) {
|
||||
await this.biometricsService.init();
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -3,9 +3,9 @@ import { ipcMain, systemPreferences } from "electron";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
|
||||
import { BiometricMain } from "../biometric/biometric.main";
|
||||
import { BiometricsServiceAbstraction } from "./biometrics.service.abstraction";
|
||||
|
||||
export default class BiometricDarwinMain implements BiometricMain {
|
||||
export default class BiometricDarwinMain implements BiometricsServiceAbstraction {
|
||||
constructor(private i18nservice: I18nService, private stateService: StateService) {}
|
||||
|
||||
async init() {
|
||||
|
||||
@@ -7,9 +7,9 @@ import { biometrics } from "@bitwarden/desktop-native";
|
||||
|
||||
import { WindowMain } from "../window.main";
|
||||
|
||||
import { BiometricMain } from "./biometric.main";
|
||||
import { BiometricsServiceAbstraction } from "./biometrics.service.abstraction";
|
||||
|
||||
export default class BiometricWindowsMain implements BiometricMain {
|
||||
export default class BiometricWindowsMain implements BiometricsServiceAbstraction {
|
||||
constructor(
|
||||
private i18nservice: I18nService,
|
||||
private windowMain: WindowMain,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export abstract class BiometricMain {
|
||||
export abstract class BiometricsServiceAbstraction {
|
||||
init: () => Promise<void>;
|
||||
supportsBiometric: () => Promise<boolean>;
|
||||
authenticateBiometric: () => Promise<boolean>;
|
||||
83
apps/desktop/src/main/biometric/biometrics.service.spec.ts
Normal file
83
apps/desktop/src/main/biometric/biometrics.service.spec.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
|
||||
import { WindowMain } from "../window.main";
|
||||
|
||||
import BiometricDarwinMain from "./biometric.darwin.main";
|
||||
import BiometricWindowsMain from "./biometric.windows.main";
|
||||
import { BiometricsService } from "./biometrics.service";
|
||||
import { BiometricsServiceAbstraction } from "./biometrics.service.abstraction";
|
||||
|
||||
describe("biometrics tests", function () {
|
||||
const i18nService = mock<I18nService>();
|
||||
const windowMain = mock<WindowMain>();
|
||||
const stateService = mock<StateService>();
|
||||
const logService = mock<LogService>();
|
||||
|
||||
it("Should call the platformspecific methods", () => {
|
||||
const sut = new BiometricsService(i18nService, windowMain, stateService, logService);
|
||||
|
||||
const mockService = mock<BiometricsServiceAbstraction>();
|
||||
(sut as any).platformSpecificService = mockService;
|
||||
sut.init();
|
||||
expect(mockService.init).toBeCalled();
|
||||
|
||||
sut.supportsBiometric();
|
||||
expect(mockService.supportsBiometric).toBeCalled();
|
||||
|
||||
sut.authenticateBiometric();
|
||||
expect(mockService.authenticateBiometric).toBeCalled();
|
||||
});
|
||||
|
||||
describe("win32 process platform", function () {
|
||||
let originalPlatform: NodeJS.Platform = null;
|
||||
|
||||
beforeAll(function () {
|
||||
originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: "win32",
|
||||
});
|
||||
});
|
||||
|
||||
const sut = new BiometricsService(i18nService, windowMain, stateService, logService);
|
||||
|
||||
it("Should create a biometrics service specific for Windows", () => {
|
||||
const internalService = (sut as any).platformSpecificService;
|
||||
expect(internalService).not.toBeNull();
|
||||
expect(internalService).toBeInstanceOf(BiometricWindowsMain);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: originalPlatform,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("darwin process platform", function () {
|
||||
let originalPlatform: NodeJS.Platform = null;
|
||||
|
||||
beforeAll(function () {
|
||||
originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: "darwin",
|
||||
});
|
||||
});
|
||||
|
||||
it("Should create a biometrics service specific for MacOs", () => {
|
||||
const sut = new BiometricsService(i18nService, windowMain, stateService, logService);
|
||||
const internalService = (sut as any).platformSpecificService;
|
||||
expect(internalService).not.toBeNull();
|
||||
expect(internalService).toBeInstanceOf(BiometricDarwinMain);
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: originalPlatform,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
57
apps/desktop/src/main/biometric/biometrics.service.ts
Normal file
57
apps/desktop/src/main/biometric/biometrics.service.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
|
||||
import { WindowMain } from "../window.main";
|
||||
|
||||
import { BiometricsServiceAbstraction } from "./biometrics.service.abstraction";
|
||||
|
||||
export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
private platformSpecificService: BiometricsServiceAbstraction;
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private windowMain: WindowMain,
|
||||
private stateService: StateService,
|
||||
private logService: LogService
|
||||
) {
|
||||
this.loadPlatformSpecificService();
|
||||
}
|
||||
|
||||
private loadPlatformSpecificService() {
|
||||
if (process.platform === "win32") {
|
||||
this.loadWindowsHelloService();
|
||||
} else if (process.platform === "darwin") {
|
||||
this.loadMacOSService();
|
||||
}
|
||||
}
|
||||
|
||||
private loadWindowsHelloService() {
|
||||
// eslint-disable-next-line
|
||||
const BiometricWindowsMain = require("./biometric.windows.main").default;
|
||||
this.platformSpecificService = new BiometricWindowsMain(
|
||||
this.i18nService,
|
||||
this.windowMain,
|
||||
this.stateService,
|
||||
this.logService
|
||||
);
|
||||
}
|
||||
|
||||
private loadMacOSService() {
|
||||
// eslint-disable-next-line
|
||||
const BiometricDarwinMain = require("./biometric.darwin.main").default;
|
||||
this.platformSpecificService = new BiometricDarwinMain(this.i18nService, this.stateService);
|
||||
}
|
||||
|
||||
async init() {
|
||||
return await this.platformSpecificService.init();
|
||||
}
|
||||
|
||||
async supportsBiometric(): Promise<boolean> {
|
||||
return await this.platformSpecificService.supportsBiometric();
|
||||
}
|
||||
|
||||
async authenticateBiometric(): Promise<boolean> {
|
||||
return await this.platformSpecificService.authenticateBiometric();
|
||||
}
|
||||
}
|
||||
2
apps/desktop/src/main/biometric/index.ts
Normal file
2
apps/desktop/src/main/biometric/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./biometrics.service.abstraction";
|
||||
export * from "./biometrics.service";
|
||||
@@ -2,13 +2,16 @@ import { ipcMain } from "electron";
|
||||
|
||||
import { passwords } from "@bitwarden/desktop-native";
|
||||
|
||||
import { BiometricMain } from "./biometric/biometric.main";
|
||||
import { BiometricsServiceAbstraction } from "./biometric/index";
|
||||
|
||||
const AuthRequiredSuffix = "_biometric";
|
||||
const AuthenticatedActions = ["getPassword"];
|
||||
|
||||
export class DesktopCredentialStorageListener {
|
||||
constructor(private serviceName: string, private biometricService: BiometricMain) {}
|
||||
constructor(
|
||||
private serviceName: string,
|
||||
private biometricService: BiometricsServiceAbstraction
|
||||
) {}
|
||||
|
||||
init() {
|
||||
ipcMain.handle("keytar", async (event: any, message: any) => {
|
||||
|
||||
Reference in New Issue
Block a user