mirror of
https://github.com/bitwarden/browser
synced 2025-12-21 10:43:35 +00:00
[PM-21705] Require userID for refreshAdditionalKeys() on key-service (#14810)
* Require userID for refreshAdditionalKeys() * Add error handling to desktop Unlock settings * Add more unit test coverage
This commit is contained in:
@@ -37,6 +37,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums/theme-type.enum";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
@@ -162,6 +163,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
private logService: LogService,
|
||||
private nativeMessagingManifestService: NativeMessagingManifestService,
|
||||
private configService: ConfigService,
|
||||
private validationService: ValidationService,
|
||||
) {
|
||||
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||
|
||||
@@ -379,7 +381,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
this.form.controls.pin.valueChanges
|
||||
.pipe(
|
||||
concatMap(async (value) => {
|
||||
await this.updatePin(value);
|
||||
await this.updatePinHandler(value);
|
||||
this.refreshTimeoutSettings$.next();
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
@@ -389,7 +391,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
this.form.controls.biometric.valueChanges
|
||||
.pipe(
|
||||
concatMap(async (enabled) => {
|
||||
await this.updateBiometric(enabled);
|
||||
await this.updateBiometricHandler(enabled);
|
||||
this.refreshTimeoutSettings$.next();
|
||||
}),
|
||||
takeUntil(this.destroy$),
|
||||
@@ -485,6 +487,18 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
async updatePinHandler(value: boolean) {
|
||||
try {
|
||||
await this.updatePin(value);
|
||||
} catch (error) {
|
||||
this.logService.error("Error updating unlock with PIN: ", error);
|
||||
this.form.controls.pin.setValue(!value, { emitEvent: false });
|
||||
this.validationService.showError(error);
|
||||
} finally {
|
||||
this.messagingService.send("redrawMenu");
|
||||
}
|
||||
}
|
||||
|
||||
async updatePin(value: boolean) {
|
||||
if (value) {
|
||||
const dialogRef = SetPinComponent.open(this.dialogService);
|
||||
@@ -509,8 +523,18 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.vaultTimeoutSettingsService.clear(userId);
|
||||
}
|
||||
}
|
||||
|
||||
this.messagingService.send("redrawMenu");
|
||||
async updateBiometricHandler(value: boolean) {
|
||||
try {
|
||||
await this.updateBiometric(value);
|
||||
} catch (error) {
|
||||
this.logService.error("Error updating unlock with biometrics: ", error);
|
||||
this.form.controls.biometric.setValue(false, { emitEvent: false });
|
||||
this.validationService.showError(error);
|
||||
} finally {
|
||||
this.messagingService.send("redrawMenu");
|
||||
}
|
||||
}
|
||||
|
||||
async updateBiometric(enabled: boolean) {
|
||||
@@ -519,61 +543,55 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
// The bug should resolve itself once the angular issue is resolved.
|
||||
// See: https://github.com/angular/angular/issues/13063
|
||||
|
||||
try {
|
||||
if (!enabled || !this.supportsBiometric) {
|
||||
this.form.controls.biometric.setValue(false, { emitEvent: false });
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(false);
|
||||
await this.keyService.refreshAdditionalKeys();
|
||||
return;
|
||||
}
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (!enabled || !this.supportsBiometric) {
|
||||
this.form.controls.biometric.setValue(false, { emitEvent: false });
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(false);
|
||||
await this.keyService.refreshAdditionalKeys(activeUserId);
|
||||
return;
|
||||
}
|
||||
|
||||
const status = await this.biometricsService.getBiometricsStatus();
|
||||
const status = await this.biometricsService.getBiometricsStatus();
|
||||
|
||||
if (status === BiometricsStatus.AutoSetupNeeded) {
|
||||
await this.biometricsService.setupBiometrics();
|
||||
} else if (status === BiometricsStatus.ManualSetupNeeded) {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "biometricsManualSetupTitle" },
|
||||
content: { key: "biometricsManualSetupDesc" },
|
||||
type: "warning",
|
||||
});
|
||||
if (confirmed) {
|
||||
this.platformUtilsService.launchUri("https://bitwarden.com/help/biometrics/");
|
||||
}
|
||||
return;
|
||||
if (status === BiometricsStatus.AutoSetupNeeded) {
|
||||
await this.biometricsService.setupBiometrics();
|
||||
} else if (status === BiometricsStatus.ManualSetupNeeded) {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "biometricsManualSetupTitle" },
|
||||
content: { key: "biometricsManualSetupDesc" },
|
||||
type: "warning",
|
||||
});
|
||||
if (confirmed) {
|
||||
this.platformUtilsService.launchUri("https://bitwarden.com/help/biometrics/");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(true);
|
||||
if (this.isWindows) {
|
||||
// Recommended settings for Windows Hello
|
||||
this.form.controls.requirePasswordOnStart.setValue(true);
|
||||
this.form.controls.autoPromptBiometrics.setValue(false);
|
||||
await this.biometricStateService.setPromptAutomatically(false);
|
||||
await this.biometricStateService.setRequirePasswordOnStart(true);
|
||||
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
|
||||
} else if (this.isLinux) {
|
||||
// Similar to Windows
|
||||
this.form.controls.requirePasswordOnStart.setValue(true);
|
||||
this.form.controls.autoPromptBiometrics.setValue(false);
|
||||
await this.biometricStateService.setPromptAutomatically(false);
|
||||
await this.biometricStateService.setRequirePasswordOnStart(true);
|
||||
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
|
||||
}
|
||||
await this.keyService.refreshAdditionalKeys();
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(true);
|
||||
if (this.isWindows) {
|
||||
// Recommended settings for Windows Hello
|
||||
this.form.controls.requirePasswordOnStart.setValue(true);
|
||||
this.form.controls.autoPromptBiometrics.setValue(false);
|
||||
await this.biometricStateService.setPromptAutomatically(false);
|
||||
await this.biometricStateService.setRequirePasswordOnStart(true);
|
||||
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
|
||||
} else if (this.isLinux) {
|
||||
// Similar to Windows
|
||||
this.form.controls.requirePasswordOnStart.setValue(true);
|
||||
this.form.controls.autoPromptBiometrics.setValue(false);
|
||||
await this.biometricStateService.setPromptAutomatically(false);
|
||||
await this.biometricStateService.setRequirePasswordOnStart(true);
|
||||
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
|
||||
}
|
||||
await this.keyService.refreshAdditionalKeys(activeUserId);
|
||||
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
// Validate the key is stored in case biometrics fail.
|
||||
const biometricSet =
|
||||
(await this.biometricsService.getBiometricsStatusForUser(activeUserId)) ===
|
||||
BiometricsStatus.Available;
|
||||
this.form.controls.biometric.setValue(biometricSet, { emitEvent: false });
|
||||
if (!biometricSet) {
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(false);
|
||||
}
|
||||
} finally {
|
||||
this.messagingService.send("redrawMenu");
|
||||
// Validate the key is stored in case biometrics fail.
|
||||
const biometricSet =
|
||||
(await this.biometricsService.getBiometricsStatusForUser(activeUserId)) ===
|
||||
BiometricsStatus.Available;
|
||||
this.form.controls.biometric.setValue(biometricSet, { emitEvent: false });
|
||||
if (!biometricSet) {
|
||||
await this.biometricStateService.setBiometricUnlockEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,7 +617,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
await this.biometricStateService.setRequirePasswordOnStart(false);
|
||||
}
|
||||
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
|
||||
await this.keyService.refreshAdditionalKeys();
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.keyService.refreshAdditionalKeys(userId);
|
||||
}
|
||||
|
||||
async saveFavicons() {
|
||||
|
||||
Reference in New Issue
Block a user