diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 5354fe5e4e1..ca584a831b2 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1251,7 +1251,10 @@ "message": "Unlock with biometric" }, "awaitDesktop": { - "message": "Awaiting biometric confirmation from desktop application." + "message": "Awaiting confirmation from desktop" + }, + "awaitDesktopDesc": { + "message": "Please confirm using biometrics in the Bitwarden desktop application to enable biometrics for browser." }, "lockWithMasterPassOnRestart": { "message": "Lock with master password on browser restart" diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 19758b94374..27916cef21f 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -141,8 +141,6 @@ export default class MainBackground { private nativeMessagingBackground: NativeMessagingBackground; constructor() { - this.nativeMessagingBackground = new NativeMessagingBackground(); - // Services this.messagingService = new BrowserMessagingService(); this.platformUtilsService = new BrowserPlatformUtilsService(this.messagingService, @@ -150,7 +148,14 @@ export default class MainBackground { if (this.systemService != null) { this.systemService.clearClipboard(clipboardValue, clearMs); } - }, this.nativeMessagingBackground); + }, + () => { + if (this.nativeMessagingBackground != null) { + const promise = this.nativeMessagingBackground.await(); + this.nativeMessagingBackground.send({command: 'biometricUnlock'}) + return promise.then((result) => result.response === 'unlocked'); + } + }); this.storageService = new BrowserStorageService(this.platformUtilsService); this.secureStorageService = new BrowserStorageService(this.platformUtilsService); this.i18nService = new I18nService(BrowserApi.getUILanguage(window)); @@ -228,6 +233,7 @@ export default class MainBackground { this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, this.analytics, this.notificationsService, this.systemService, this.vaultTimeoutService, this.environmentService); + this.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.vaultTimeoutService, this.runtimeBackground); this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, this.platformUtilsService, this.analytics, this.vaultTimeoutService); diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index 30028acb8c4..7b3b93c7ff8 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -1,4 +1,8 @@ +import { CryptoService, VaultTimeoutService } from 'jslib/abstractions'; +import { StorageService } from 'jslib/abstractions/storage.service'; +import { ConstantsService } from 'jslib/services'; import { BrowserApi } from '../browser/browserApi'; +import RuntimeBackground from './runtime.background'; export class NativeMessagingBackground { private connected = false; @@ -6,18 +10,16 @@ export class NativeMessagingBackground { private resolver: any = null; + constructor(private storageService: StorageService, private cryptoService: CryptoService, + private vaultTimeoutService: VaultTimeoutService, private runtimeBackground: RuntimeBackground) {} + connect() { this.port = BrowserApi.connectNative('com.8bit.bitwarden'); this.connected = true; - this.port.onMessage.addListener((msg: any) => { - if (this.resolver) { - this.resolver(msg); - } else { - // tslint:disable-next-line - console.error('NO RESOLVER'); - } - }); + + this.port.onMessage.addListener((msg) => this.onMessage(msg)); + this.port.onDisconnect.addListener(() => { this.connected = false; }); @@ -37,4 +39,30 @@ export class NativeMessagingBackground { this.resolver = resolve; }); } + + private async onMessage(msg: any) { + switch(msg.command) { + case 'biometricUnlock': { + await this.storageService.remove(ConstantsService.biometricAwaitingAcceptance); + + const enabled = await this.storageService.get(ConstantsService.biometricUnlockKey); + if (enabled === null || enabled === false) { + if (msg.response === 'unlocked') { + await this.storageService.save(ConstantsService.biometricUnlockKey, true); + } + + await this.cryptoService.toggleKey(); + } + + if (this.vaultTimeoutService.biometricLocked) { + this.runtimeBackground.processMessage({command: 'unlocked'}, null, null); + this.vaultTimeoutService.biometricLocked = false; + } + } + } + + if (this.resolver) { + this.resolver(msg); + } + } } diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index aea6b05b1f3..8f0ebf7cd62 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -22,6 +22,7 @@ import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service'; import { BrowserApi } from '../browser/browserApi'; import MainBackground from './main.background'; +import { NativeMessagingBackground } from './nativeMessaging.background'; import { Analytics } from 'jslib/misc'; import { Utils } from 'jslib/misc/utils'; diff --git a/src/popup/settings/settings.component.ts b/src/popup/settings/settings.component.ts index 6d1c06463b8..1029fe29f13 100644 --- a/src/popup/settings/settings.component.ts +++ b/src/popup/settings/settings.component.ts @@ -51,7 +51,7 @@ export class SettingsComponent implements OnInit { vaultTimeoutActions: any[]; vaultTimeoutAction: string; pin: boolean = null; - biometric: boolean = null; + biometric: boolean = false; previousVaultTimeout: number = null; constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, @@ -207,40 +207,45 @@ export class SettingsComponent implements OnInit { } async updateBiometric() { - const current = this.biometric; if (this.biometric) { this.biometric = false; + // TODO: Remove biometric stuff + await this.storageService.remove(ConstantsService.biometricUnlockKey); + this.vaultTimeoutService.biometricLocked = false; } else { - const div = document.createElement('div'); - div.innerHTML = `