mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01:00
[PM-5537] Remove Unecessary Biometric State (#7762)
* Create state for biometric client key halves * Move enc string util to central utils * Provide biometric state through service * Use biometric state to track client key half * Create migration for client key half * Ensure client key half is removed on logout * Remove account data for client key half * Remove unnecessary key definition likes * Remove moved state from account * Fix null-conditional operator failure * Simplify migration * Remove lame test * Fix test type * Add migrator * Remove state that is never read. * Remove unnecessary biometric state We don't need to determine platform in desktop background, it can be done in the UI at any time. * Fix merge * Use platform utils to identify OS desktop type
This commit is contained in:
parent
fae12cd0e6
commit
c8c1ed42ba
@ -296,8 +296,6 @@ export class NativeMessagingBackground {
|
||||
|
||||
switch (message.command) {
|
||||
case "biometricUnlock": {
|
||||
await this.stateService.setBiometricAwaitingAcceptance(null);
|
||||
|
||||
if (message.response === "not enabled") {
|
||||
this.messagingService.send("showDialog", {
|
||||
title: { key: "biometricsNotEnabledTitle" },
|
||||
|
@ -369,14 +369,12 @@ export class SettingsComponent implements OnInit {
|
||||
const awaitDesktopDialogRef = AwaitDesktopDialogComponent.open(this.dialogService);
|
||||
const awaitDesktopDialogClosed = firstValueFrom(awaitDesktopDialogRef.closed);
|
||||
|
||||
await this.stateService.setBiometricAwaitingAcceptance(true);
|
||||
await this.cryptoService.refreshAdditionalKeys();
|
||||
|
||||
await Promise.race([
|
||||
awaitDesktopDialogClosed.then(async (result) => {
|
||||
if (result !== true) {
|
||||
this.form.controls.biometric.setValue(false);
|
||||
await this.stateService.setBiometricAwaitingAcceptance(null);
|
||||
}
|
||||
}),
|
||||
this.platformUtilsService
|
||||
|
@ -24,6 +24,7 @@ import { DialogService } from "@bitwarden/components";
|
||||
import { SetPinComponent } from "../../auth/components/set-pin.component";
|
||||
import { flagEnabled } from "../../platform/flags";
|
||||
import { ElectronStateService } from "../../platform/services/electron-state.service.abstraction";
|
||||
|
||||
@Component({
|
||||
selector: "app-settings",
|
||||
templateUrl: "settings.component.html",
|
||||
@ -39,9 +40,7 @@ export class SettingsComponent implements OnInit {
|
||||
themeOptions: any[];
|
||||
clearClipboardOptions: any[];
|
||||
supportsBiometric: boolean;
|
||||
biometricText: string;
|
||||
additionalBiometricSettingsText: string;
|
||||
autoPromptBiometricsText: string;
|
||||
showAlwaysShowDock = false;
|
||||
requireEnableTray = false;
|
||||
showDuckDuckGoIntegrationOption = false;
|
||||
@ -275,12 +274,10 @@ export class SettingsComponent implements OnInit {
|
||||
this.showMinToTray = this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop;
|
||||
this.showAlwaysShowDock = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
|
||||
this.biometricText = await this.stateService.getBiometricText();
|
||||
this.additionalBiometricSettingsText =
|
||||
this.biometricText === "unlockWithTouchId"
|
||||
? "additionalTouchIdSettings"
|
||||
: "additionalWindowsHelloSettings";
|
||||
this.autoPromptBiometricsText = await this.stateService.getNoAutoPromptBiometricsText();
|
||||
this.previousVaultTimeout = this.form.value.vaultTimeout;
|
||||
|
||||
this.refreshTimeoutSettings$
|
||||
@ -667,4 +664,26 @@ export class SettingsComponent implements OnInit {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
get biometricText() {
|
||||
switch (this.platformUtilsService.getDevice()) {
|
||||
case DeviceType.MacOsDesktop:
|
||||
return "unlockWithTouchId";
|
||||
case DeviceType.WindowsDesktop:
|
||||
return "unlockWithWindowsHello";
|
||||
default:
|
||||
throw new Error("Unsupported platform");
|
||||
}
|
||||
}
|
||||
|
||||
get autoPromptBiometricsText() {
|
||||
switch (this.platformUtilsService.getDevice()) {
|
||||
case DeviceType.MacOsDesktop:
|
||||
return "autoPromptTouchId";
|
||||
case DeviceType.WindowsDesktop:
|
||||
return "autoPromptWindowsHello";
|
||||
default:
|
||||
throw new Error("Unsupported platform");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,4 +185,15 @@ export class LockComponent extends BaseLockComponent {
|
||||
await this.stateService.setDismissedBiometricRequirePasswordOnStart();
|
||||
}
|
||||
}
|
||||
|
||||
get biometricText() {
|
||||
switch (this.platformUtilsService.getDevice()) {
|
||||
case DeviceType.MacOsDesktop:
|
||||
return "unlockWithTouchId";
|
||||
case DeviceType.WindowsDesktop:
|
||||
return "unlockWithWindowsHello";
|
||||
default:
|
||||
throw new Error("Unsupported platform");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,9 +225,6 @@ export class Main {
|
||||
}
|
||||
this.powerMonitorMain.init();
|
||||
await this.updaterMain.init();
|
||||
if (this.biometricsService != null) {
|
||||
await this.biometricsService.init();
|
||||
}
|
||||
|
||||
if (
|
||||
(await this.stateService.getEnableBrowserIntegration()) ||
|
||||
|
@ -1,21 +1,12 @@
|
||||
import { systemPreferences } from "electron";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { passwords } from "@bitwarden/desktop-native";
|
||||
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
|
||||
export default class BiometricDarwinMain implements OsBiometricService {
|
||||
constructor(
|
||||
private i18nservice: I18nService,
|
||||
private stateService: StateService,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
await this.stateService.setBiometricText("unlockWithTouchId");
|
||||
await this.stateService.setNoAutoPromptBiometricsText("autoPromptTouchId");
|
||||
}
|
||||
constructor(private i18nservice: I18nService) {}
|
||||
|
||||
async osSupportsBiometric(): Promise<boolean> {
|
||||
return systemPreferences.canPromptTouchID();
|
||||
|
@ -5,7 +5,6 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym
|
||||
import { biometrics, passwords } from "@bitwarden/desktop-native";
|
||||
|
||||
import { WindowMain } from "../../../main/window.main";
|
||||
import { ElectronStateService } from "../../services/electron-state.service.abstraction";
|
||||
|
||||
import { OsBiometricService } from "./biometrics.service.abstraction";
|
||||
|
||||
@ -21,15 +20,9 @@ export default class BiometricWindowsMain implements OsBiometricService {
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private windowMain: WindowMain,
|
||||
private stateService: ElectronStateService,
|
||||
private logService: LogService,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
await this.stateService.setBiometricText("unlockWithWindowsHello");
|
||||
await this.stateService.setNoAutoPromptBiometricsText("autoPromptWindowsHello");
|
||||
}
|
||||
|
||||
async osSupportsBiometric(): Promise<boolean> {
|
||||
return await biometrics.available();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
export abstract class BiometricsServiceAbstraction {
|
||||
init: () => Promise<void>;
|
||||
osSupportsBiometric: () => Promise<boolean>;
|
||||
canAuthBiometric: ({
|
||||
service,
|
||||
@ -26,7 +25,6 @@ export abstract class BiometricsServiceAbstraction {
|
||||
}
|
||||
|
||||
export interface OsBiometricService {
|
||||
init: () => Promise<void>;
|
||||
osSupportsBiometric: () => Promise<boolean>;
|
||||
authenticateBiometric: () => Promise<boolean>;
|
||||
getBiometricKey: (
|
||||
|
@ -43,13 +43,7 @@ describe("biometrics tests", function () {
|
||||
|
||||
const mockService = mock<OsBiometricService>();
|
||||
(sut as any).platformSpecificService = mockService;
|
||||
// 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
|
||||
sut.init();
|
||||
// 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
|
||||
sut.setEncryptionKeyHalf({ service: "test", key: "test", value: "test" });
|
||||
expect(mockService.init).toBeCalled();
|
||||
await sut.setEncryptionKeyHalf({ service: "test", key: "test", value: "test" });
|
||||
|
||||
await sut.canAuthBiometric({ service: "test", key: "test", userId });
|
||||
expect(mockService.osSupportsBiometric).toBeCalled();
|
||||
@ -111,9 +105,6 @@ describe("biometrics tests", function () {
|
||||
|
||||
innerService = mock();
|
||||
(sut as any).platformSpecificService = innerService;
|
||||
// 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
|
||||
sut.init();
|
||||
});
|
||||
|
||||
it("should return false if client key half is required and not provided", async () => {
|
||||
@ -128,7 +119,6 @@ describe("biometrics tests", function () {
|
||||
// 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
|
||||
sut.setEncryptionKeyHalf({ service: "test", key: "test", value: "test" });
|
||||
expect(innerService.init).toBeCalled();
|
||||
|
||||
await sut.canAuthBiometric({ service: "test", key: "test", userId });
|
||||
expect(innerService.osSupportsBiometric).toBeCalled();
|
||||
|
@ -58,10 +58,6 @@ export class BiometricsService implements BiometricsServiceAbstraction {
|
||||
this.platformSpecificService = new NoopBiometricsService();
|
||||
}
|
||||
|
||||
async init() {
|
||||
return await this.platformSpecificService.init();
|
||||
}
|
||||
|
||||
async osSupportsBiometric() {
|
||||
return await this.platformSpecificService.osSupportsBiometric();
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
formPromise: Promise<MasterPasswordPolicyResponse>;
|
||||
supportsBiometric: boolean;
|
||||
biometricLock: boolean;
|
||||
biometricText: string;
|
||||
|
||||
protected successRoute = "vault";
|
||||
protected forcePasswordResetRoute = "update-temp-password";
|
||||
@ -343,7 +342,6 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
(await this.vaultTimeoutSettingsService.isBiometricLockSet()) &&
|
||||
((await this.cryptoService.hasUserKeyStored(KeySuffixOptions.Biometric)) ||
|
||||
!this.platformUtilsService.supportsSecureStorage());
|
||||
this.biometricText = await this.stateService.getBiometricText();
|
||||
this.email = await this.stateService.getEmail();
|
||||
|
||||
this.webVaultHostname = await this.environmentService.getHost();
|
||||
|
@ -69,12 +69,8 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setApiKeyClientSecret: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getAutoConfirmFingerPrints: (options?: StorageOptions) => Promise<boolean>;
|
||||
setAutoConfirmFingerprints: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricAwaitingAcceptance: (options?: StorageOptions) => Promise<boolean>;
|
||||
setBiometricAwaitingAcceptance: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
||||
setBiometricFingerprintValidated: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricText: (options?: StorageOptions) => Promise<string>;
|
||||
setBiometricText: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricUnlock: (options?: StorageOptions) => Promise<boolean>;
|
||||
setBiometricUnlock: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getCanAccessPremium: (options?: StorageOptions) => Promise<boolean>;
|
||||
@ -378,8 +374,6 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setMinimizeOnCopyToClipboard: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getNeverDomains: (options?: StorageOptions) => Promise<{ [id: string]: unknown }>;
|
||||
setNeverDomains: (value: { [id: string]: unknown }, options?: StorageOptions) => Promise<void>;
|
||||
getNoAutoPromptBiometricsText: (options?: StorageOptions) => Promise<string>;
|
||||
setNoAutoPromptBiometricsText: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getOpenAtLogin: (options?: StorageOptions) => Promise<boolean>;
|
||||
setOpenAtLogin: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getOrganizationInvitation: (options?: StorageOptions) => Promise<any>;
|
||||
|
@ -11,15 +11,11 @@ export class GlobalState {
|
||||
window?: WindowState = new WindowState();
|
||||
twoFactorToken?: string;
|
||||
disableFavicon?: boolean;
|
||||
biometricAwaitingAcceptance?: boolean;
|
||||
biometricFingerprintValidated?: boolean;
|
||||
vaultTimeout?: number;
|
||||
vaultTimeoutAction?: string;
|
||||
loginRedirect?: any;
|
||||
mainWindowSize?: number;
|
||||
enableBiometrics?: boolean;
|
||||
biometricText?: string;
|
||||
noAutoPromptBiometricsText?: string;
|
||||
enableTray?: boolean;
|
||||
enableMinimizeToTray?: boolean;
|
||||
enableCloseToTray?: boolean;
|
||||
|
@ -372,24 +372,6 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
async getBiometricAwaitingAcceptance(options?: StorageOptions): Promise<boolean> {
|
||||
return (
|
||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||
?.biometricAwaitingAcceptance ?? false
|
||||
);
|
||||
}
|
||||
|
||||
async setBiometricAwaitingAcceptance(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
const globals = await this.getGlobals(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
globals.biometricAwaitingAcceptance = value;
|
||||
await this.saveGlobals(
|
||||
globals,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
async getBiometricFingerprintValidated(options?: StorageOptions): Promise<boolean> {
|
||||
return (
|
||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||
@ -408,23 +390,6 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
async getBiometricText(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.biometricText;
|
||||
}
|
||||
|
||||
async setBiometricText(value: string, options?: StorageOptions): Promise<void> {
|
||||
const globals = await this.getGlobals(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
globals.biometricText = value;
|
||||
await this.saveGlobals(
|
||||
globals,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
async getBiometricUnlock(options?: StorageOptions): Promise<boolean> {
|
||||
return (
|
||||
(await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||
@ -1989,23 +1954,6 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
async getNoAutoPromptBiometricsText(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.noAutoPromptBiometricsText;
|
||||
}
|
||||
|
||||
async setNoAutoPromptBiometricsText(value: string, options?: StorageOptions): Promise<void> {
|
||||
const globals = await this.getGlobals(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
globals.noAutoPromptBiometricsText = value;
|
||||
await this.saveGlobals(
|
||||
globals,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
async getOpenAtLogin(options?: StorageOptions): Promise<boolean> {
|
||||
return (
|
||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
||||
|
Loading…
Reference in New Issue
Block a user