From 5ad0e87093a397a579f334c18bfdbefe5510f529 Mon Sep 17 00:00:00 2001 From: Todd Martin Date: Sun, 7 Jul 2024 16:34:36 -0400 Subject: [PATCH] Changed method names and added documentation --- .../main/biometric/biometric.darwin.main.ts | 6 +- .../main/biometric/biometric.noop.main.ts | 6 +- .../main/biometric/biometric.windows.main.ts | 6 +- .../biometrics.service.abstraction.ts | 67 +++++++++++++++---- .../main/biometric/biometrics.service.ts | 25 ++++--- .../desktop-credential-storage-listener.ts | 12 ++-- 6 files changed, 86 insertions(+), 36 deletions(-) diff --git a/apps/desktop/src/platform/main/biometric/biometric.darwin.main.ts b/apps/desktop/src/platform/main/biometric/biometric.darwin.main.ts index e1a5c3da9a..8659590fed 100644 --- a/apps/desktop/src/platform/main/biometric/biometric.darwin.main.ts +++ b/apps/desktop/src/platform/main/biometric/biometric.darwin.main.ts @@ -21,7 +21,7 @@ export default class BiometricDarwinMain implements OsBiometricService { } } - async getBiometricKey(service: string, key: string): Promise { + async getBiometricEncryptedData(service: string, key: string): Promise { const success = await this.authenticateBiometric(); if (!success) { @@ -31,7 +31,7 @@ export default class BiometricDarwinMain implements OsBiometricService { return await passwords.getPassword(service, key); } - async setBiometricKey(service: string, key: string, value: string): Promise { + async setBiometricEncryptedData(service: string, key: string, value: string): Promise { if (await this.valueUpToDate(service, key, value)) { return; } @@ -39,7 +39,7 @@ export default class BiometricDarwinMain implements OsBiometricService { return await passwords.setPassword(service, key, value); } - async deleteBiometricKey(service: string, key: string): Promise { + async deleteBiometricEncryptedData(service: string, key: string): Promise { return await passwords.deletePassword(service, key); } diff --git a/apps/desktop/src/platform/main/biometric/biometric.noop.main.ts b/apps/desktop/src/platform/main/biometric/biometric.noop.main.ts index 152b5ce32f..77484cb7b8 100644 --- a/apps/desktop/src/platform/main/biometric/biometric.noop.main.ts +++ b/apps/desktop/src/platform/main/biometric/biometric.noop.main.ts @@ -9,7 +9,7 @@ export default class NoopBiometricsService implements OsBiometricService { return false; } - async getBiometricKey( + async getBiometricEncryptedData( service: string, storageKey: string, clientKeyHalfB64: string, @@ -17,7 +17,7 @@ export default class NoopBiometricsService implements OsBiometricService { return null; } - async setBiometricKey( + async setBiometricEncryptedData( service: string, storageKey: string, value: string, @@ -26,7 +26,7 @@ export default class NoopBiometricsService implements OsBiometricService { return; } - async deleteBiometricKey(service: string, key: string): Promise {} + async deleteBiometricEncryptedData(service: string, key: string): Promise {} async authenticateBiometric(): Promise { throw new Error("Not supported on this platform"); diff --git a/apps/desktop/src/platform/main/biometric/biometric.windows.main.ts b/apps/desktop/src/platform/main/biometric/biometric.windows.main.ts index 75d5bce8f5..4b2ad15d8b 100644 --- a/apps/desktop/src/platform/main/biometric/biometric.windows.main.ts +++ b/apps/desktop/src/platform/main/biometric/biometric.windows.main.ts @@ -27,7 +27,7 @@ export default class BiometricWindowsMain implements OsBiometricService { return await biometrics.available(); } - async getBiometricKey( + async getBiometricEncryptedData( service: string, storageKey: string, clientKeyHalfB64: string, @@ -60,7 +60,7 @@ export default class BiometricWindowsMain implements OsBiometricService { } } - async setBiometricKey( + async setBiometricEncryptedData( service: string, storageKey: string, value: string, @@ -89,7 +89,7 @@ export default class BiometricWindowsMain implements OsBiometricService { ); } - async deleteBiometricKey(service: string, key: string): Promise { + async deleteBiometricEncryptedData(service: string, key: string): Promise { await passwords.deletePassword(service, key); await passwords.deletePassword(service, key + KEY_WITNESS_SUFFIX); } diff --git a/apps/desktop/src/platform/main/biometric/biometrics.service.abstraction.ts b/apps/desktop/src/platform/main/biometric/biometrics.service.abstraction.ts index fb7ce048b5..b3cd8b21fc 100644 --- a/apps/desktop/src/platform/main/biometric/biometrics.service.abstraction.ts +++ b/apps/desktop/src/platform/main/biometric/biometrics.service.abstraction.ts @@ -1,42 +1,85 @@ export abstract class BiometricsServiceAbstraction { + /** + * Checks if the OS supports biometric authentication. + * @returns True if the OS supports biometric authentication, false otherwise. + */ abstract osSupportsBiometric(): Promise; + /** + * Checks to see if the user can authenticate using biometric authentication by ensuring that + * the OS supports biometric authentication and that the user has registered a client key half if configured. + * @param service The name of the service under which the client key half shoul be registered. + * @param storageKey The name with which the client key half shoul be registered. + * @param userId The `userID` for which the client key half should be registered. + * @returns True if the user can authenticate using biometric authentication, false otherwise. + */ abstract canAuthBiometric({ service, - key, + storageKey, userId, }: { service: string; - key: string; + storageKey: string; userId: string; }): Promise; + /** + * Authenticates the user using biometric authentication. + * @returns True if the user was successfully authenticated, false otherwise. + */ abstract authenticateBiometric(): Promise; - abstract getBiometricKey(service: string, key: string): Promise; - abstract setBiometricKey(service: string, key: string, value: string): Promise; + /** + * Retrieves data from the platform's secure storage after decrypting with a biometrically-derived key. + * @param service The name of the service under which the key is registered. + * @param storageKey The name with which the key is stored in secure storage. + * @returns The decrypted data, or null if the data could not be retrieved. + */ + abstract getBiometricEncryptedData(service: string, storageKey: string): Promise; + /** + * Sets data in the platform's secure storage after encrypting with a biometrically-derived key. + * @param service The name of the service under which the data should be registered. + * @param storageKey The name with which the data is stored in secure storage. + * @param value The data to store. + */ + abstract setBiometricEncryptedData( + service: string, + storageKey: string, + value: string, + ): Promise; + /** + * Registers the client key half for encrypting and decrypting the data stored in `storageKey`. The other half is protected by the OS. + * @param service The name of the service under which the key should be registered. + * @param storageKey The name with which the data is stored in secure storage. + * @param value The client-side encryption key half to store. + */ abstract setEncryptionKeyHalf({ service, - key, + storageKey, value, }: { service: string; - key: string; + storageKey: string; value: string; }): void; - abstract deleteBiometricKey(service: string, key: string): Promise; + /** + * Deletes the biometrically-protected data stored under `storageKey`. + * @param service The name of the service under which the key was registered. + * @param storageKey The name with which the key was stored in secure storage. + */ + abstract deleteBiometricEncryptedData(service: string, storageKey: string): Promise; } export interface OsBiometricService { osSupportsBiometric(): Promise; authenticateBiometric(): Promise; - getBiometricKey( + getBiometricEncryptedData( service: string, - key: string, + storageKey: string, clientKeyHalfB64: string | undefined, ): Promise; - setBiometricKey( + setBiometricEncryptedData( service: string, - key: string, + storageKey: string, value: string, clientKeyHalfB64: string | undefined, ): Promise; - deleteBiometricKey(service: string, key: string): Promise; + deleteBiometricEncryptedData(service: string, storageKey: string): Promise; } diff --git a/apps/desktop/src/platform/main/biometric/biometrics.service.ts b/apps/desktop/src/platform/main/biometric/biometrics.service.ts index b0331cce3e..eeaa48f743 100644 --- a/apps/desktop/src/platform/main/biometric/biometrics.service.ts +++ b/apps/desktop/src/platform/main/biometric/biometrics.service.ts @@ -90,11 +90,11 @@ export class BiometricsService implements BiometricsServiceAbstraction { return result; } - async getBiometricKey(service: string, storageKey: string): Promise { + async getBiometricEncryptedData(service: string, storageKey: string): Promise { return await this.interruptProcessReload(async () => { await this.enforceClientKeyHalf(service, storageKey); - return await this.platformSpecificService.getBiometricKey( + return await this.platformSpecificService.getBiometricEncryptedData( service, storageKey, this.getClientKeyHalf(service, storageKey), @@ -102,10 +102,14 @@ export class BiometricsService implements BiometricsServiceAbstraction { }); } - async setBiometricKey(service: string, storageKey: string, value: string): Promise { + async setBiometricEncryptedData( + service: string, + storageKey: string, + value: string, + ): Promise { await this.enforceClientKeyHalf(service, storageKey); - return await this.platformSpecificService.setBiometricKey( + return await this.platformSpecificService.setBiometricEncryptedData( service, storageKey, value, @@ -113,26 +117,25 @@ export class BiometricsService implements BiometricsServiceAbstraction { ); } - /** Registers the client-side encryption key half for the OS stored Biometric key. The other half is protected by the OS.*/ async setEncryptionKeyHalf({ service, - key, + storageKey, value, }: { service: string; - key: string; + storageKey: string; value: string; }): Promise { if (value == null) { - this.clientKeyHalves.delete(this.clientKeyHalfKey(service, key)); + this.clientKeyHalves.delete(this.clientKeyHalfKey(service, storageKey)); } else { - this.clientKeyHalves.set(this.clientKeyHalfKey(service, key), value); + this.clientKeyHalves.set(this.clientKeyHalfKey(service, storageKey), value); } } - async deleteBiometricKey(service: string, storageKey: string): Promise { + async deleteBiometricEncryptedData(service: string, storageKey: string): Promise { this.clientKeyHalves.delete(this.clientKeyHalfKey(service, storageKey)); - return await this.platformSpecificService.deleteBiometricKey(service, storageKey); + return await this.platformSpecificService.deleteBiometricEncryptedData(service, storageKey); } private async interruptProcessReload( diff --git a/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts b/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts index adc7935e05..f46ba70c7d 100644 --- a/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts +++ b/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts @@ -93,7 +93,7 @@ export class DesktopCredentialStorageListener { private async getPassword(serviceName: string, key: string, keySuffix: string) { let val: string; if (keySuffix === AuthRequiredSuffix) { - val = (await this.biometricService.getBiometricKey(serviceName, key)) ?? null; + val = (await this.biometricService.getBiometricEncryptedData(serviceName, key)) ?? null; } else { val = await passwords.getPassword(serviceName, key); } @@ -112,11 +112,15 @@ export class DesktopCredentialStorageListener { const valueObj = JSON.parse(value) as BiometricKey; await this.biometricService.setEncryptionKeyHalf({ service: serviceName, - key, + storageKey: key, value: valueObj?.clientEncKeyHalf, }); // Value is usually a JSON string, but we need to pass the key half as well, so we re-stringify key here. - await this.biometricService.setBiometricKey(serviceName, key, JSON.stringify(valueObj?.key)); + await this.biometricService.setBiometricEncryptedData( + serviceName, + key, + JSON.stringify(valueObj?.key), + ); } else { await passwords.setPassword(serviceName, key, value); } @@ -124,7 +128,7 @@ export class DesktopCredentialStorageListener { private async deletePassword(serviceName: string, key: string, keySuffix: string) { if (keySuffix === AuthRequiredSuffix) { - await this.biometricService.deleteBiometricKey(serviceName, key); + await this.biometricService.deleteBiometricEncryptedData(serviceName, key); } else { await passwords.deletePassword(serviceName, key); }