diff --git a/src/abstractions/biometric.main.ts b/src/abstractions/biometric.main.ts index 0f85cc1f55..eff805ea32 100644 --- a/src/abstractions/biometric.main.ts +++ b/src/abstractions/biometric.main.ts @@ -1,4 +1,5 @@ export abstract class BiometricMain { + isError: boolean; init: () => Promise; supportsBiometric: () => Promise; requestCreate: () => Promise; diff --git a/src/electron/biometric.darwin.main.ts b/src/electron/biometric.darwin.main.ts index ab449654ef..11ebc23565 100644 --- a/src/electron/biometric.darwin.main.ts +++ b/src/electron/biometric.darwin.main.ts @@ -6,6 +6,8 @@ import { ConstantsService } from '../services'; import { ElectronConstants } from './electronConstants'; export default class BiometricDarwinMain implements BiometricMain { + isError: boolean = false; + constructor(private storageService: StorageService, private i18nservice: I18nService) {} async init() { diff --git a/src/electron/biometric.windows.main.ts b/src/electron/biometric.windows.main.ts index 5a0d089965..c8948bd4f1 100644 --- a/src/electron/biometric.windows.main.ts +++ b/src/electron/biometric.windows.main.ts @@ -1,10 +1,3 @@ -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'; @@ -12,19 +5,23 @@ 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) {} + isError: boolean = false; + + private windowsSecurityCredentialsUiModule: any; + + constructor(private storageService: StorageService, private i18nservice: I18nService) { } async init() { - this.storageService.save(ElectronConstants.enableBiometric, await this.supportsBiometric()); + this.windowsSecurityCredentialsUiModule = this.getWindowsSecurityCredentialsUiModule(); + let supportsBiometric = false; + try { + supportsBiometric = await this.supportsBiometric(); + } catch { + // store error state so we can let the user know on the settings page + this.isError = true; + } + this.storageService.save(ElectronConstants.enableBiometric, supportsBiometric); this.storageService.save(ConstantsService.biometricText, 'unlockWithWindowsHello'); ipcMain.on('biometric', async (event: any, message: any) => { @@ -33,14 +30,72 @@ export default class BiometricWindowsMain implements BiometricMain { } async supportsBiometric(): Promise { - const availability = await checkAvailability(); + const availability = await this.checkAvailabilityAsync(); - return AllowedAvailabilities.includes(availability); + return this.getAllowedAvailabilities().includes(availability); } async requestCreate(): Promise { - const verification = await requestVerification(this.i18nservice.t('windowsHelloConsentMessage')); + const module = this.getWindowsSecurityCredentialsUiModule(); + if (module == null) { + return false; + } - return verification === UserConsentVerificationResult.verified; + const verification = await this.requestVerificationAsync(this.i18nservice.t('windowsHelloConsentMessage')); + + return verification === module.UserConsentVerificationResult.verified; + } + + getWindowsSecurityCredentialsUiModule(): any { + try { + return null; + /* + return this._windowsSecurityCredentialsUiModule || + require('@nodert-win10-rs4/windows.security.credentials.ui'); + */ + } catch { + this.isError = true; + } + } + + async checkAvailabilityAsync(): Promise { + const module = this.getWindowsSecurityCredentialsUiModule(); + if (module != null) { + return new Promise((resolve, reject) => { + module.UserConsentVerifier.checkAvailabilityAsync((error: Error, result: any) => { + if (error) { + return resolve(null); + } + return resolve(result); + }); + }); + } + return Promise.resolve(null); + } + + async requestVerificationAsync(message: string): Promise { + const module = this.getWindowsSecurityCredentialsUiModule(); + if (module != null) { + return new Promise((resolve, reject) => { + module.UserConsentVerifier.requestVerificationAsync(message, (error: Error, result: any) => { + if (error) { + return resolve(null); + } + return resolve(result); + }); + }); + } + return Promise.resolve(null); + } + + getAllowedAvailabilities(): any[] { + const module = this.getWindowsSecurityCredentialsUiModule(); + if (module != null) { + return [ + module.UserConsentVerifierAvailability.available, + module.UserConsentVerifierAvailability.deviceBusy, + ]; + } + return []; } } diff --git a/src/globals.d.ts b/src/globals.d.ts index 4c123c15a8..8116ab173f 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -1,104 +1,3 @@ declare function escape(s: string): string; declare function unescape(s: string): string; declare module 'duo_web_sdk'; - -/* tslint:disable */ -declare module '@nodert-win10-rs4/windows.security.credentials.ui' { - export enum AuthenticationProtocol { - basic, - digest, - ntlm, - kerberos, - negotiate, - credSsp, - custom, - } - - export enum CredentialSaveOption { - unselected, - selected, - hidden, - } - - export enum UserConsentVerifierAvailability { - available, - deviceNotPresent, - notConfiguredForUser, - disabledByPolicy, - deviceBusy, - } - - export enum UserConsentVerificationResult { - verified, - deviceNotPresent, - notConfiguredForUser, - disabledByPolicy, - deviceBusy, - retriesExhausted, - canceled, - } - - export class CredentialPickerOptions { - targetName: String; - previousCredential: Object; - message: String; - errorCode: Number; - customAuthenticationProtocol: String; - credentialSaveOption: CredentialSaveOption; - caption: String; - callerSavesCredential: Boolean; - authenticationProtocol: AuthenticationProtocol; - alwaysDisplayDialog: Boolean; - constructor(); - } - - export class CredentialPickerResults { - credential: Object; - credentialDomainName: String; - credentialPassword: String; - credentialSaveOption: CredentialSaveOption; - credentialSaved: Boolean; - credentialUserName: String; - errorCode: Number; - constructor(); - } - - export class CredentialPicker { - constructor(); - - static pickAsync( - options: CredentialPickerOptions, - callback: (error: Error, result: CredentialPickerResults) => void - ): void; - static pickAsync( - targetName: String, - message: String, - callback: (error: Error, result: CredentialPickerResults) => void - ): void; - static pickAsync( - targetName: String, - message: String, - caption: String, - callback: (error: Error, result: CredentialPickerResults) => void - ): void; - } - - export class UserConsentVerifier { - constructor(); - - static checkAvailabilityAsync( - callback: ( - error: Error, - result: UserConsentVerifierAvailability - ) => void - ): void; - - static requestVerificationAsync( - message: String, - callback: ( - error: Error, - result: UserConsentVerificationResult - ) => void - ): void; - } -}