1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-08 03:23:50 +00:00

Desktop biometrics support (#119)

* Initial work on windows hello support

* Switch to use windows.security.credentials.ui UserConsentVerifier

* Fix linting warnings

* Remove unessesary supportsBiometric from lock screen

* Rename biometric.main to windows.biometric.main. Add abstraction for biometric.

* Add support for dynamic biometric text.

* Add untested darwin implementation

* Rename fingerprintUnlock to biometric

* Add new functions to cliPlatformUtils.service.ts.

* Hide login if biometric is not supported

* Export default for biometric.*.main.ts

* Remove @nodert-win10-rs4/windows.security.credentials

* Add build requirements to readme

* Auto prompt biometric when starting the application.

* Ensure we support biometric before trying to auto prompt.

* Fix review comments and linting errors
This commit is contained in:
Oscar Hinton
2020-07-23 19:32:20 +02:00
committed by GitHub
parent 94d363bfca
commit c62f5287cd
19 changed files with 300 additions and 6 deletions

View File

@@ -0,0 +1,32 @@
import { I18nService, StorageService } from '../abstractions';
import { ipcMain, systemPreferences } from 'electron';
import { BiometricMain } from '../abstractions/biometric.main';
import { ConstantsService } from '../services';
import { ElectronConstants } from './electronConstants';
export default class BiometricDarwinMain implements BiometricMain {
constructor(private storageService: StorageService, private i18nservice: I18nService) {}
async init() {
this.storageService.save(ElectronConstants.enableBiometric, await this.supportsBiometric());
this.storageService.save(ConstantsService.biometricText, 'unlockWithTouchId');
ipcMain.on('biometric', async (event: any, message: any) => {
event.returnValue = await this.requestCreate();
});
}
supportsBiometric(): Promise<boolean> {
return Promise.resolve(systemPreferences.canPromptTouchID());
}
async requestCreate(): Promise<boolean> {
try {
await systemPreferences.promptTouchID(this.i18nservice.t('touchIdConsentMessage'));
return true;
} catch {
return false;
}
}
}

View File

@@ -0,0 +1,46 @@
import * as util from 'util';
import {
UserConsentVerificationResult,
UserConsentVerifier,
UserConsentVerifierAvailability,
} from '@nodert-win10-rs4/windows.security.credentials.ui';
import { I18nService, StorageService } from '../abstractions';
import { ipcMain } from 'electron';
import { BiometricMain } from '../abstractions/biometric.main';
import { ConstantsService } from '../services';
import { ElectronConstants } from './electronConstants';
const requestVerification: any = util.promisify(UserConsentVerifier.requestVerificationAsync);
const checkAvailability: any = util.promisify(UserConsentVerifier.checkAvailabilityAsync);
const AllowedAvailabilities = [
UserConsentVerifierAvailability.available,
UserConsentVerifierAvailability.deviceBusy,
];
export default class BiometricWindowsMain implements BiometricMain {
constructor(private storageService: StorageService, private i18nservice: I18nService) {}
async init() {
this.storageService.save(ElectronConstants.enableBiometric, await this.supportsBiometric());
this.storageService.save(ConstantsService.biometricText, 'unlockWithWindowsHello');
ipcMain.on('biometric', async (event: any, message: any) => {
event.returnValue = await this.requestCreate();
});
}
async supportsBiometric(): Promise<boolean> {
const availability = await checkAvailability();
return AllowedAvailabilities.includes(availability);
}
async requestCreate(): Promise<boolean> {
const verification = await requestVerification(this.i18nservice.t('windowsHelloConsentMessage'));
return verification === UserConsentVerificationResult.verified;
}
}

View File

@@ -5,4 +5,5 @@ export class ElectronConstants {
static readonly enableStartToTrayKey: string = 'enableStartToTrayKey';
static readonly enableAlwaysOnTopKey: string = 'enableAlwaysOnTopKey';
static readonly minimizeOnCopyToClipboardKey: string = 'minimizeOnCopyToClipboardKey';
static readonly enableBiometric: string = 'enabledBiometric';
}

View File

@@ -1,5 +1,6 @@
import {
clipboard,
ipcRenderer,
remote,
shell,
} from 'electron';
@@ -15,8 +16,10 @@ import { DeviceType } from '../../enums/deviceType';
import { I18nService } from '../../abstractions/i18n.service';
import { MessagingService } from '../../abstractions/messaging.service';
import { PlatformUtilsService } from '../../abstractions/platformUtils.service';
import { StorageService } from '../../abstractions/storage.service';
import { AnalyticsIds } from '../../misc/analytics';
import { ElectronConstants } from '../electronConstants';
export class ElectronPlatformUtilsService implements PlatformUtilsService {
identityClientId: string;
@@ -25,7 +28,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
private analyticsIdCache: string = null;
constructor(private i18nService: I18nService, private messagingService: MessagingService,
private isDesktopApp: boolean) {
private isDesktopApp: boolean, private storageService: StorageService) {
this.identityClientId = isDesktopApp ? 'desktop' : 'connector';
}
@@ -203,4 +206,17 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
const type = options ? options.type : null;
return Promise.resolve(clipboard.readText(type));
}
supportsBiometric(): Promise<boolean> {
return this.storageService.get(ElectronConstants.enableBiometric);
}
authenticateBiometric(): Promise<boolean> {
return new Promise((resolve) => {
const val = ipcRenderer.sendSync('biometric', {
action: 'authenticate',
});
resolve(val);
});
}
}