1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 13:53:34 +00:00

cleanup remove password on start for desktop (#15957)

This commit is contained in:
Maciej Zieniuk
2025-08-22 23:14:02 +02:00
committed by GitHub
parent 65230a9c3e
commit 5b402d9c38
9 changed files with 5 additions and 302 deletions

View File

@@ -97,31 +97,6 @@
</label>
</div>
</div>
<div
class="form-group"
*ngIf="
supportsBiometric &&
this.form.value.biometric &&
(userHasMasterPassword || (this.form.value.pin && userHasPinSet)) &&
false
"
>
<div class="checkbox form-group-child">
<label for="requirePasswordOnStart">
<input
id="requirePasswordOnStart"
type="checkbox"
formControlName="requirePasswordOnStart"
(change)="updateRequirePasswordOnStart()"
/>
@if (pinEnabled$ | async) {
{{ "requirePasswordOnStart" | i18n }}
} @else {
{{ "requirePasswordWithoutPinOnStart" | i18n }}
}
</label>
</div>
</div>
</ng-container>
</div>
</div>

View File

@@ -157,7 +157,6 @@ describe("SettingsComponent", () => {
);
vaultTimeoutSettingsService.isBiometricLockSet.mockResolvedValue(false);
biometricStateService.promptAutomatically$ = of(false);
biometricStateService.requirePasswordOnStart$ = of(false);
autofillSettingsServiceAbstraction.clearClipboardDelay$ = of(null);
desktopSettingsService.minimizeOnCopy$ = of(false);
desktopSettingsService.trayEnabled$ = of(false);
@@ -378,48 +377,14 @@ describe("SettingsComponent", () => {
});
describe("when updating to false", () => {
let updateRequirePasswordOnStartSpy: jest.SpyInstance;
beforeEach(() => {
updateRequirePasswordOnStartSpy = jest
.spyOn(component, "updateRequirePasswordOnStart")
.mockImplementation(() => Promise.resolve());
});
it("updates requires password on start when the user doesn't have a MP and has requirePasswordOnStart on", async () => {
it("sets the pin form control to false and clears vault timeout", async () => {
await component.ngOnInit();
component.form.controls.requirePasswordOnStart.setValue(true, { emitEvent: false });
component.userHasMasterPassword = false;
await component.updatePinHandler(false);
expect(component.form.controls.pin.value).toBe(false);
expect(component.form.controls.requirePasswordOnStart.value).toBe(false);
expect(updateRequirePasswordOnStartSpy).toHaveBeenCalled();
expect(vaultTimeoutSettingsService.clear).toHaveBeenCalled();
expect(messagingService.send).toHaveBeenCalledWith("redrawMenu");
});
test.each([
[true, true],
[false, true],
[false, false],
])(
`doesn't updates requires password on start when the user's requirePasswordOnStart is %s and userHasMasterPassword is %s`,
async (requirePasswordOnStart, userHasMasterPassword) => {
await component.ngOnInit();
component.form.controls.requirePasswordOnStart.setValue(requirePasswordOnStart, {
emitEvent: false,
});
component.userHasMasterPassword = userHasMasterPassword;
await component.updatePinHandler(false);
expect(component.form.controls.pin.value).toBe(false);
expect(component.form.controls.requirePasswordOnStart.value).toBe(requirePasswordOnStart);
expect(updateRequirePasswordOnStartSpy).not.toHaveBeenCalled();
expect(vaultTimeoutSettingsService.clear).toHaveBeenCalled();
expect(messagingService.send).toHaveBeenCalledWith("redrawMenu");
},
);
});
});
@@ -512,11 +477,8 @@ describe("SettingsComponent", () => {
await component.updateBiometricHandler(true);
expect(biometricStateService.setBiometricUnlockEnabled).toHaveBeenCalledWith(true);
expect(component.form.controls.requirePasswordOnStart.value).toBe(true);
expect(component.form.controls.autoPromptBiometrics.value).toBe(false);
expect(biometricStateService.setPromptAutomatically).toHaveBeenCalledWith(false);
expect(biometricStateService.setRequirePasswordOnStart).toHaveBeenCalledWith(true);
expect(biometricStateService.setDismissedRequirePasswordOnStartCallout).toHaveBeenCalled();
expect(keyService.refreshAdditionalKeys).toHaveBeenCalledWith(mockUserId);
expect(component.form.controls.biometric.value).toBe(true);
expect(messagingService.send).toHaveBeenCalledWith("redrawMenu");
@@ -533,11 +495,8 @@ describe("SettingsComponent", () => {
await component.updateBiometricHandler(true);
expect(biometricStateService.setBiometricUnlockEnabled).toHaveBeenCalledWith(true);
expect(component.form.controls.requirePasswordOnStart.value).toBe(true);
expect(component.form.controls.autoPromptBiometrics.value).toBe(false);
expect(biometricStateService.setPromptAutomatically).toHaveBeenCalledWith(false);
expect(biometricStateService.setRequirePasswordOnStart).toHaveBeenCalledWith(true);
expect(biometricStateService.setDismissedRequirePasswordOnStartCallout).toHaveBeenCalled();
expect(keyService.refreshAdditionalKeys).toHaveBeenCalledWith(mockUserId);
expect(component.form.controls.biometric.value).toBe(true);
expect(messagingService.send).toHaveBeenCalledWith("redrawMenu");

View File

@@ -135,7 +135,6 @@ export class SettingsComponent implements OnInit, OnDestroy {
pin: [null as boolean | null],
biometric: false,
autoPromptBiometrics: false,
requirePasswordOnStart: false,
// Account Preferences
clearClipboard: [null],
minimizeOnCopyToClipboard: false,
@@ -350,9 +349,6 @@ export class SettingsComponent implements OnInit, OnDestroy {
pin: this.userHasPinSet,
biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(),
autoPromptBiometrics: await firstValueFrom(this.biometricStateService.promptAutomatically$),
requirePasswordOnStart: await firstValueFrom(
this.biometricStateService.requirePasswordOnStart$,
),
clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$),
minimizeOnCopyToClipboard: await firstValueFrom(this.desktopSettingsService.minimizeOnCopy$),
enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$),
@@ -557,16 +553,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.userHasPinSet = await firstValueFrom(dialogRef.closed);
this.form.controls.pin.setValue(this.userHasPinSet, { emitEvent: false });
}
if (!value) {
// If user turned off PIN without having a MP and has biometric + require MP/PIN on restart enabled
if (this.form.value.requirePasswordOnStart && !this.userHasMasterPassword) {
// then must turn that off to prevent user from getting into bad state
this.form.controls.requirePasswordOnStart.setValue(false);
await this.updateRequirePasswordOnStart();
}
} else {
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.vaultTimeoutSettingsService.clear(userId);
}
@@ -617,18 +604,12 @@ export class SettingsComponent implements OnInit, OnDestroy {
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);
@@ -644,30 +625,12 @@ export class SettingsComponent implements OnInit, OnDestroy {
async updateAutoPromptBiometrics() {
if (this.form.value.autoPromptBiometrics) {
// require password on start must be disabled if auto prompt biometrics is enabled
this.form.controls.requirePasswordOnStart.setValue(false);
await this.updateRequirePasswordOnStart();
await this.biometricStateService.setPromptAutomatically(true);
} else {
await this.biometricStateService.setPromptAutomatically(false);
}
}
async updateRequirePasswordOnStart() {
if (this.form.value.requirePasswordOnStart) {
// auto prompt biometrics must be disabled if require password on start is enabled
this.form.controls.autoPromptBiometrics.setValue(false);
await this.updateAutoPromptBiometrics();
await this.biometricStateService.setRequirePasswordOnStart(true);
} else {
await this.biometricStateService.setRequirePasswordOnStart(false);
}
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.keyService.refreshAdditionalKeys(userId);
}
async saveFavicons() {
await this.domainSettingsService.setShowFavicons(this.form.value.enableFavicons);
this.messagingService.send("refreshCiphers");

View File

@@ -198,11 +198,6 @@ export default class OsBiometricsServiceLinux implements OsBiometricService {
userId: UserId,
key: SymmetricCryptoKey,
): Promise<Uint8Array | null> {
const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId);
if (!requireClientKeyHalf) {
return null;
}
if (this.clientKeyHalves.has(userId)) {
return this.clientKeyHalves.get(userId) || null;
}
@@ -227,12 +222,10 @@ export default class OsBiometricsServiceLinux implements OsBiometricService {
}
async getBiometricsFirstUnlockStatusForUser(userId: UserId): Promise<BiometricsStatus> {
const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId);
const clientKeyHalfB64 = this.clientKeyHalves.get(userId);
const clientKeyHalfSatisfied = !requireClientKeyHalf || !!clientKeyHalfB64;
if (!clientKeyHalfSatisfied) {
if (this.clientKeyHalves.has(userId)) {
return BiometricsStatus.Available;
} else {
return BiometricsStatus.UnlockNeeded;
}
return BiometricsStatus.Available;
}
}

View File

@@ -1846,12 +1846,6 @@
"autoPromptTouchId": {
"message": "Ask for Touch ID on app start"
},
"requirePasswordOnStart": {
"message": "Require password or PIN on app start"
},
"requirePasswordWithoutPinOnStart": {
"message": "Require password on app start"
},
"lockWithMasterPassOnRestart1": {
"message": "Lock with master password on restart"
},