mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-06 23:51:28 +01:00
Move fingerprint validated to biometric state povider (#8058)
This commit is contained in:
parent
eedd6f0881
commit
f83dcf2b24
@ -814,6 +814,7 @@ export default class MainBackground {
|
||||
this.stateService,
|
||||
this.autofillSettingsService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.biometricStateService,
|
||||
);
|
||||
|
||||
// Other fields
|
||||
|
@ -84,10 +84,6 @@ export class NativeMessagingBackground {
|
||||
private authService: AuthService,
|
||||
private biometricStateService: BiometricStateService,
|
||||
) {
|
||||
// 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
|
||||
this.stateService.setBiometricFingerprintValidated(false);
|
||||
|
||||
if (chrome?.permissions?.onAdded) {
|
||||
// Reload extension to activate nativeMessaging
|
||||
chrome.permissions.onAdded.addListener((permissions) => {
|
||||
@ -100,9 +96,7 @@ export class NativeMessagingBackground {
|
||||
|
||||
async connect() {
|
||||
this.appId = await this.appIdService.getAppId();
|
||||
// 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
|
||||
this.stateService.setBiometricFingerprintValidated(false);
|
||||
await this.biometricStateService.setFingerprintValidated(false);
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.port = BrowserApi.connectNative("com.8bit.bitwarden");
|
||||
@ -148,9 +142,7 @@ export class NativeMessagingBackground {
|
||||
|
||||
if (this.validatingFingerprint) {
|
||||
this.validatingFingerprint = false;
|
||||
// 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
|
||||
this.stateService.setBiometricFingerprintValidated(true);
|
||||
await this.biometricStateService.setFingerprintValidated(true);
|
||||
}
|
||||
this.sharedSecret = new SymmetricCryptoKey(decrypted);
|
||||
this.secureSetupResolve();
|
||||
|
@ -415,7 +415,7 @@ export class SettingsComponent implements OnInit {
|
||||
]);
|
||||
} else {
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(false);
|
||||
await this.stateService.setBiometricFingerprintValidated(false);
|
||||
await this.biometricStateService.setFingerprintValidated(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
||||
StateServiceAbstraction,
|
||||
AutofillSettingsServiceAbstraction,
|
||||
VaultTimeoutSettingsService,
|
||||
BiometricStateService,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
BIOMETRIC_UNLOCK_ENABLED,
|
||||
DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT,
|
||||
ENCRYPTED_CLIENT_KEY_HALF,
|
||||
FINGERPRINT_VALIDATED,
|
||||
PROMPT_AUTOMATICALLY,
|
||||
PROMPT_CANCELLED,
|
||||
REQUIRE_PASSWORD_ON_START,
|
||||
@ -67,6 +68,19 @@ describe("BiometricStateService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("fingerprintValidated$", () => {
|
||||
it("emits when the fingerprint validated state changes", async () => {
|
||||
const state = stateProvider.global.getFake(FINGERPRINT_VALIDATED);
|
||||
state.stateSubject.next(undefined);
|
||||
|
||||
expect(await firstValueFrom(sut.fingerprintValidated$)).toBe(false);
|
||||
|
||||
state.stateSubject.next(true);
|
||||
|
||||
expect(await firstValueFrom(sut.fingerprintValidated$)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setEncryptedClientKeyHalf", () => {
|
||||
it("updates encryptedClientKeyHalf$", async () => {
|
||||
await sut.setEncryptedClientKeyHalf(encClientKeyHalf);
|
||||
@ -207,4 +221,20 @@ describe("BiometricStateService", () => {
|
||||
expect(await sut.getBiometricUnlockEnabled(userId)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setFingerprintValidated", () => {
|
||||
it("updates fingerprintValidated$", async () => {
|
||||
await sut.setFingerprintValidated(true);
|
||||
|
||||
expect(await firstValueFrom(sut.fingerprintValidated$)).toBe(true);
|
||||
});
|
||||
|
||||
it("updates state", async () => {
|
||||
await sut.setFingerprintValidated(true);
|
||||
|
||||
expect(stateProvider.global.getFake(FINGERPRINT_VALIDATED).nextMock).toHaveBeenCalledWith(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import { Observable, firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { UserId } from "../../types/guid";
|
||||
import { EncryptedString, EncString } from "../models/domain/enc-string";
|
||||
import { ActiveUserState, StateProvider } from "../state";
|
||||
import { ActiveUserState, GlobalState, StateProvider } from "../state";
|
||||
|
||||
import {
|
||||
BIOMETRIC_UNLOCK_ENABLED,
|
||||
@ -11,6 +11,7 @@ import {
|
||||
DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT,
|
||||
PROMPT_AUTOMATICALLY,
|
||||
PROMPT_CANCELLED,
|
||||
FINGERPRINT_VALIDATED,
|
||||
} from "./biometric.state";
|
||||
|
||||
export abstract class BiometricStateService {
|
||||
@ -49,6 +50,10 @@ export abstract class BiometricStateService {
|
||||
* tracks the currently active user
|
||||
*/
|
||||
promptAutomatically$: Observable<boolean>;
|
||||
/**
|
||||
* Whether or not IPC fingerprint has been validated by the user this session.
|
||||
*/
|
||||
fingerprintValidated$: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Updates the require password on start state for the currently active user.
|
||||
@ -88,6 +93,11 @@ export abstract class BiometricStateService {
|
||||
* @param prompt Whether or not to prompt for biometrics on application start.
|
||||
*/
|
||||
abstract setPromptAutomatically(prompt: boolean): Promise<void>;
|
||||
/**
|
||||
* Updates whether or not IPC has been validated by the user this session
|
||||
* @param validated the value to save
|
||||
*/
|
||||
abstract setFingerprintValidated(validated: boolean): Promise<void>;
|
||||
|
||||
abstract logout(userId: UserId): Promise<void>;
|
||||
}
|
||||
@ -99,12 +109,14 @@ export class DefaultBiometricStateService implements BiometricStateService {
|
||||
private dismissedRequirePasswordOnStartCalloutState: ActiveUserState<boolean>;
|
||||
private promptCancelledState: ActiveUserState<boolean>;
|
||||
private promptAutomaticallyState: ActiveUserState<boolean>;
|
||||
private fingerprintValidatedState: GlobalState<boolean>;
|
||||
biometricUnlockEnabled$: Observable<boolean>;
|
||||
encryptedClientKeyHalf$: Observable<EncString | undefined>;
|
||||
requirePasswordOnStart$: Observable<boolean>;
|
||||
dismissedRequirePasswordOnStartCallout$: Observable<boolean>;
|
||||
promptCancelled$: Observable<boolean>;
|
||||
promptAutomatically$: Observable<boolean>;
|
||||
fingerprintValidated$: Observable<boolean>;
|
||||
|
||||
constructor(private stateProvider: StateProvider) {
|
||||
this.biometricUnlockEnabledState = this.stateProvider.getActive(BIOMETRIC_UNLOCK_ENABLED);
|
||||
@ -130,6 +142,9 @@ export class DefaultBiometricStateService implements BiometricStateService {
|
||||
this.promptCancelled$ = this.promptCancelledState.state$.pipe(map(Boolean));
|
||||
this.promptAutomaticallyState = this.stateProvider.getActive(PROMPT_AUTOMATICALLY);
|
||||
this.promptAutomatically$ = this.promptAutomaticallyState.state$.pipe(map(Boolean));
|
||||
|
||||
this.fingerprintValidatedState = this.stateProvider.getGlobal(FINGERPRINT_VALIDATED);
|
||||
this.fingerprintValidated$ = this.fingerprintValidatedState.state$.pipe(map(Boolean));
|
||||
}
|
||||
|
||||
async setBiometricUnlockEnabled(enabled: boolean): Promise<void> {
|
||||
@ -207,6 +222,10 @@ export class DefaultBiometricStateService implements BiometricStateService {
|
||||
async setPromptAutomatically(prompt: boolean): Promise<void> {
|
||||
await this.promptAutomaticallyState.update(() => prompt);
|
||||
}
|
||||
|
||||
async setFingerprintValidated(validated: boolean): Promise<void> {
|
||||
await this.fingerprintValidatedState.update(() => validated);
|
||||
}
|
||||
}
|
||||
|
||||
function encryptedClientKeyHalfToEncString(
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
BIOMETRIC_UNLOCK_ENABLED,
|
||||
DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT,
|
||||
ENCRYPTED_CLIENT_KEY_HALF,
|
||||
FINGERPRINT_VALIDATED,
|
||||
PROMPT_AUTOMATICALLY,
|
||||
PROMPT_CANCELLED,
|
||||
REQUIRE_PASSWORD_ON_START,
|
||||
@ -16,7 +17,8 @@ describe.each([
|
||||
[PROMPT_CANCELLED, true],
|
||||
[PROMPT_AUTOMATICALLY, true],
|
||||
[REQUIRE_PASSWORD_ON_START, true],
|
||||
[BIOMETRIC_UNLOCK_ENABLED, "test"],
|
||||
[BIOMETRIC_UNLOCK_ENABLED, true],
|
||||
[FINGERPRINT_VALIDATED, true],
|
||||
])(
|
||||
"deserializes state %s",
|
||||
(
|
||||
|
@ -74,3 +74,14 @@ export const PROMPT_AUTOMATICALLY = new KeyDefinition<boolean>(
|
||||
deserializer: (obj) => obj,
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Stores whether or not IPC handshake has been validated this session.
|
||||
*/
|
||||
export const FINGERPRINT_VALIDATED = new KeyDefinition<boolean>(
|
||||
BIOMETRIC_SETTINGS_DISK,
|
||||
"fingerprintValidated",
|
||||
{
|
||||
deserializer: (obj) => obj,
|
||||
},
|
||||
);
|
||||
|
@ -9,6 +9,7 @@ import { MessagingService } from "../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platform-utils.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import { SystemService as SystemServiceAbstraction } from "../abstractions/system.service";
|
||||
import { BiometricStateService } from "../biometrics/biometric-state.service";
|
||||
import { Utils } from "../misc/utils";
|
||||
|
||||
export class SystemService implements SystemServiceAbstraction {
|
||||
@ -23,6 +24,7 @@ export class SystemService implements SystemServiceAbstraction {
|
||||
private stateService: StateService,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
private biometricStateService: BiometricStateService,
|
||||
) {}
|
||||
|
||||
async startProcessReload(authService: AuthService): Promise<void> {
|
||||
@ -54,8 +56,9 @@ export class SystemService implements SystemServiceAbstraction {
|
||||
}
|
||||
|
||||
private async executeProcessReload() {
|
||||
const biometricLockedFingerprintValidated =
|
||||
await this.stateService.getBiometricFingerprintValidated();
|
||||
const biometricLockedFingerprintValidated = await firstValueFrom(
|
||||
this.biometricStateService.fingerprintValidated$,
|
||||
);
|
||||
if (!biometricLockedFingerprintValidated) {
|
||||
clearInterval(this.reloadInterval);
|
||||
this.reloadInterval = null;
|
||||
|
Loading…
Reference in New Issue
Block a user