mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +00:00
[PM-17038] Fix biometrics autoprompt in firefox and chrome (#12853)
* Fix biometrics not working in firefox or windows * Remove logs * Update badge after biometric unlock * Add removal todo note * Remove debug logging * Fix type warnings * Fix userkey typing in background biometrics service * Simplify types for userkey in foreground-browser-biometrics and runtime.background.ts * Add process reload logging * Fix autoprompt not working when no process reload happened * Fix instant reprompt on firefox lock * Fix biometrics enabling error on chrome * Update apps/browser/src/key-management/biometrics/foreground-browser-biometrics.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * FIx build & linting --------- Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { UserKey } from "@bitwarden/common/types/key";
|
import { UserKey } from "@bitwarden/common/types/key";
|
||||||
import { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
|
import { BiometricsCommands, BiometricsService, BiometricsStatus } from "@bitwarden/key-management";
|
||||||
@@ -34,7 +35,7 @@ export class ForegroundBrowserBiometricsService extends BiometricsService {
|
|||||||
if (!response.result) {
|
if (!response.result) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return response.result;
|
return SymmetricCryptoKey.fromString(response.result.keyB64) as UserKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
async getBiometricsStatusForUser(id: UserId): Promise<BiometricsStatus> {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
ToastOptions,
|
ToastOptions,
|
||||||
ToastService,
|
ToastService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { BiometricStateService } from "@bitwarden/key-management";
|
import { BiometricsService, BiometricStateService } from "@bitwarden/key-management";
|
||||||
|
|
||||||
import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service";
|
import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service";
|
||||||
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
|
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
|
||||||
@@ -66,6 +66,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private animationControlService: AnimationControlService,
|
private animationControlService: AnimationControlService,
|
||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
|
private biometricsService: BiometricsService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -102,7 +103,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.messageListener.allMessages$
|
this.messageListener.allMessages$
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((msg: any) => {
|
tap(async (msg: any) => {
|
||||||
if (msg.command === "doneLoggingOut") {
|
if (msg.command === "doneLoggingOut") {
|
||||||
// TODO: PM-8544 - why do we call logout in the popup after receiving the doneLoggingOut message? Hasn't this already completeted logout?
|
// TODO: PM-8544 - why do we call logout in the popup after receiving the doneLoggingOut message? Hasn't this already completeted logout?
|
||||||
this.authService.logOut(async () => {
|
this.authService.logOut(async () => {
|
||||||
@@ -119,6 +120,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
msg.command === "locked" &&
|
msg.command === "locked" &&
|
||||||
(msg.userId == null || msg.userId == this.activeUserId)
|
(msg.userId == null || msg.userId == this.activeUserId)
|
||||||
) {
|
) {
|
||||||
|
await this.biometricsService.setShouldAutopromptNow(false);
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.router.navigate(["lock"]);
|
this.router.navigate(["lock"]);
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
|
|||||||
let status = await firstValueFrom(authService.authStatusFor$(userId as UserId));
|
let status = await firstValueFrom(authService.authStatusFor$(userId as UserId));
|
||||||
status = await authService.getAuthStatus(userId);
|
status = await authService.getAuthStatus(userId);
|
||||||
if (status === AuthenticationStatus.Unlocked) {
|
if (status === AuthenticationStatus.Unlocked) {
|
||||||
|
this.logService.info(
|
||||||
|
"[Process Reload Service] User unlocked, preventing process reload",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +58,9 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
|
|||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
const ephemeralPin = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
|
const ephemeralPin = await this.pinService.getPinKeyEncryptedUserKeyEphemeral(userId);
|
||||||
if (ephemeralPin != null) {
|
if (ephemeralPin != null) {
|
||||||
|
this.logService.info(
|
||||||
|
"[Process Reload Service] Ephemeral pin active, preventing process reload",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +103,12 @@ export class DefaultProcessReloadService implements ProcessReloadServiceAbstract
|
|||||||
await this.reloadCallback();
|
await this.reloadCallback();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
this.logService.info(
|
||||||
|
"[Process Reload Service] Desktop ipc fingerprint validated, preventing process reload",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.reloadInterval == null) {
|
if (this.reloadInterval == null) {
|
||||||
this.reloadInterval = setInterval(async () => await this.executeProcessReload(), 1000);
|
this.reloadInterval = setInterval(async () => await this.executeProcessReload(), 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,10 +307,12 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
(await this.biometricService.getShouldAutopromptNow())
|
(await this.biometricService.getShouldAutopromptNow())
|
||||||
) {
|
) {
|
||||||
await this.biometricService.setShouldAutopromptNow(false);
|
await this.biometricService.setShouldAutopromptNow(false);
|
||||||
|
|
||||||
|
const lastProcessReload = await this.biometricStateService.getLastProcessReload();
|
||||||
if (
|
if (
|
||||||
(await this.biometricStateService.getLastProcessReload()) == null ||
|
lastProcessReload == null ||
|
||||||
Date.now() - (await this.biometricStateService.getLastProcessReload()).getTime() >
|
isNaN(lastProcessReload.getTime()) ||
|
||||||
AUTOPROMPT_BIOMETRICS_PROCESS_RELOAD_DELAY
|
Date.now() - lastProcessReload.getTime() > AUTOPROMPT_BIOMETRICS_PROCESS_RELOAD_DELAY
|
||||||
) {
|
) {
|
||||||
await this.unlockViaBiometrics();
|
await this.unlockViaBiometrics();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user