1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[PM-5404, PM-3518] Migrate user decryption options to new service (#7344)

* create new user decryption options service

* rename new service to user decryption options

* add hasMasterPassword to user decryption options service

* migrate device trust service to new user decryption options service

* add migration for user-decryption-options

* migrate sync service and calls to trust-device-service

* rename abstraction file

* migrate two factor component

* migrate two factor spec

* migrate sso component

* migrate set-password component

* migrate base login decryption component

* migrate organization options component

* fix component imports

* add missing imports
- remove state service calls
- add update user decryption options method

* remove acct decryption options from account

* lint

* fix tests and linting

* fix browser

* fix desktop

* add user decryption options service to cli

* remove default value from migration

* bump migration number

* fix merge conflict

* fix vault timeout settings

* fix cli

* more fixes

* add user decryption options service to deps of vault timeout settings service

* update login strategy service with user decryption options

* remove early return from sync bandaid for user decryption options

* move user decryption options service to lib/auth

* move user decryption options to libs/auth

* fix reference

* fix browser

* check user decryption options after 2fa check

* update migration and revert tsconfig changes

* add more documentation

* clear user decryption options on logout

* fix tests by creating helper for user decryption options

* fix tests

* pr feedback

* fix factory

* update migration

* add tests

* update missed migration num in test
This commit is contained in:
Jake Fink
2024-03-20 20:33:57 -04:00
committed by GitHub
parent e2fe1e1567
commit 2111b37c32
68 changed files with 1158 additions and 360 deletions

View File

@@ -1,5 +1,10 @@
import { mock, MockProxy } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { BehaviorSubject, firstValueFrom, map, of } from "rxjs";
import {
FakeUserDecryptionOptions as UserDecryptionOptions,
UserDecryptionOptionsServiceAbstraction,
} from "@bitwarden/auth/common";
import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction";
import { Policy } from "../../admin-console/models/domain/policy";
@@ -8,12 +13,12 @@ import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { StateService } from "../../platform/abstractions/state.service";
import { BiometricStateService } from "../../platform/biometrics/biometric-state.service";
import { AccountDecryptionOptions } from "../../platform/models/domain/account";
import { EncString } from "../../platform/models/domain/enc-string";
import { VaultTimeoutSettingsService } from "./vault-timeout-settings.service";
describe("VaultTimeoutSettingsService", () => {
let userDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
let cryptoService: MockProxy<CryptoService>;
let tokenService: MockProxy<TokenService>;
let policyService: MockProxy<PolicyService>;
@@ -21,12 +26,26 @@ describe("VaultTimeoutSettingsService", () => {
const biometricStateService = mock<BiometricStateService>();
let service: VaultTimeoutSettingsService;
let userDecryptionOptionsSubject: BehaviorSubject<UserDecryptionOptions>;
beforeEach(() => {
userDecryptionOptionsService = mock<UserDecryptionOptionsServiceAbstraction>();
cryptoService = mock<CryptoService>();
tokenService = mock<TokenService>();
policyService = mock<PolicyService>();
stateService = mock<StateService>();
userDecryptionOptionsSubject = new BehaviorSubject(null);
userDecryptionOptionsService.userDecryptionOptions$ = userDecryptionOptionsSubject;
userDecryptionOptionsService.hasMasterPassword$ = userDecryptionOptionsSubject.pipe(
map((options) => options?.hasMasterPassword ?? false),
);
userDecryptionOptionsService.userDecryptionOptionsById$.mockReturnValue(
userDecryptionOptionsSubject,
);
service = new VaultTimeoutSettingsService(
userDecryptionOptionsService,
cryptoService,
tokenService,
policyService,
@@ -49,9 +68,7 @@ describe("VaultTimeoutSettingsService", () => {
});
it("contains Lock when the user has a master password", async () => {
stateService.getAccountDecryptionOptions.mockResolvedValue(
new AccountDecryptionOptions({ hasMasterPassword: true }),
);
userDecryptionOptionsSubject.next(new UserDecryptionOptions({ hasMasterPassword: true }));
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
@@ -83,9 +100,7 @@ describe("VaultTimeoutSettingsService", () => {
});
it("not contains Lock when the user does not have a master password, PIN, or biometrics", async () => {
stateService.getAccountDecryptionOptions.mockResolvedValue(
new AccountDecryptionOptions({ hasMasterPassword: false }),
);
userDecryptionOptionsSubject.next(new UserDecryptionOptions({ hasMasterPassword: false }));
stateService.getPinKeyEncryptedUserKey.mockResolvedValue(null);
stateService.getProtectedPin.mockResolvedValue(null);
biometricStateService.biometricUnlockEnabled$ = of(false);
@@ -107,9 +122,7 @@ describe("VaultTimeoutSettingsService", () => {
`(
"returns $expected when policy is $policy, and user preference is $userPreference",
async ({ policy, userPreference, expected }) => {
stateService.getAccountDecryptionOptions.mockResolvedValue(
new AccountDecryptionOptions({ hasMasterPassword: true }),
);
userDecryptionOptionsSubject.next(new UserDecryptionOptions({ hasMasterPassword: true }));
policyService.getAll$.mockReturnValue(
of(policy === null ? [] : ([{ data: { action: policy } }] as unknown as Policy[])),
);
@@ -136,8 +149,8 @@ describe("VaultTimeoutSettingsService", () => {
"returns $expected when policy is $policy, has unlock method is $unlockMethod, and user preference is $userPreference",
async ({ unlockMethod, policy, userPreference, expected }) => {
biometricStateService.biometricUnlockEnabled$ = of(unlockMethod);
stateService.getAccountDecryptionOptions.mockResolvedValue(
new AccountDecryptionOptions({ hasMasterPassword: false }),
userDecryptionOptionsSubject.next(
new UserDecryptionOptions({ hasMasterPassword: false }),
);
policyService.getAll$.mockReturnValue(
of(policy === null ? [] : ([{ data: { action: policy } }] as unknown as Policy[])),

View File

@@ -1,5 +1,7 @@
import { defer, firstValueFrom } from "rxjs";
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "../../admin-console/enums";
@@ -19,6 +21,7 @@ export type PinLockType = "DISABLED" | "PERSISTANT" | "TRANSIENT";
export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceAbstraction {
constructor(
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
private cryptoService: CryptoService,
private tokenService: TokenService,
private policyService: PolicyService,
@@ -174,12 +177,15 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
}
private async userHasMasterPassword(userId: string): Promise<boolean> {
const acctDecryptionOpts = await this.stateService.getAccountDecryptionOptions({
userId: userId,
});
if (userId) {
const decryptionOptions = await firstValueFrom(
this.userDecryptionOptionsService.userDecryptionOptionsById$(userId),
);
if (acctDecryptionOpts?.hasMasterPassword != undefined) {
return acctDecryptionOpts.hasMasterPassword;
if (decryptionOptions?.hasMasterPassword != undefined) {
return decryptionOptions.hasMasterPassword;
}
}
return await firstValueFrom(this.userDecryptionOptionsService.hasMasterPassword$);
}
}