mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
* Establish biometric unlock enabled in state providers * Use biometric state service for biometric state values * Migrate biometricUnlock * Fixup Dependencies * linter and import fixes * Fix injection * Fix merge * Use boolean constructor as mapper * Conform to documented test naming conventions * Commit documentation suggestion Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com> * Fix merge commit * Fix test names --------- Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>
161 lines
7.0 KiB
TypeScript
161 lines
7.0 KiB
TypeScript
import { mock, MockProxy } from "jest-mock-extended";
|
|
import { firstValueFrom, of } from "rxjs";
|
|
|
|
import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction";
|
|
import { Policy } from "../../admin-console/models/domain/policy";
|
|
import { TokenService } from "../../auth/abstractions/token.service";
|
|
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 cryptoService: MockProxy<CryptoService>;
|
|
let tokenService: MockProxy<TokenService>;
|
|
let policyService: MockProxy<PolicyService>;
|
|
let stateService: MockProxy<StateService>;
|
|
const biometricStateService = mock<BiometricStateService>();
|
|
let service: VaultTimeoutSettingsService;
|
|
|
|
beforeEach(() => {
|
|
cryptoService = mock<CryptoService>();
|
|
tokenService = mock<TokenService>();
|
|
policyService = mock<PolicyService>();
|
|
stateService = mock<StateService>();
|
|
service = new VaultTimeoutSettingsService(
|
|
cryptoService,
|
|
tokenService,
|
|
policyService,
|
|
stateService,
|
|
biometricStateService,
|
|
);
|
|
|
|
biometricStateService.biometricUnlockEnabled$ = of(false);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.resetAllMocks();
|
|
});
|
|
|
|
describe("availableVaultTimeoutActions$", () => {
|
|
it("always returns LogOut", async () => {
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).toContain(VaultTimeoutAction.LogOut);
|
|
});
|
|
|
|
it("contains Lock when the user has a master password", async () => {
|
|
stateService.getAccountDecryptionOptions.mockResolvedValue(
|
|
new AccountDecryptionOptions({ hasMasterPassword: true }),
|
|
);
|
|
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).toContain(VaultTimeoutAction.Lock);
|
|
});
|
|
|
|
it("contains Lock when the user has a persistent PIN configured", async () => {
|
|
stateService.getPinKeyEncryptedUserKey.mockResolvedValue(createEncString());
|
|
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).toContain(VaultTimeoutAction.Lock);
|
|
});
|
|
|
|
it("contains Lock when the user has a transient/ephemeral PIN configured", async () => {
|
|
stateService.getProtectedPin.mockResolvedValue("some-key");
|
|
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).toContain(VaultTimeoutAction.Lock);
|
|
});
|
|
|
|
it("contains Lock when the user has biometrics configured", async () => {
|
|
biometricStateService.biometricUnlockEnabled$ = of(true);
|
|
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).toContain(VaultTimeoutAction.Lock);
|
|
});
|
|
|
|
it("not contains Lock when the user does not have a master password, PIN, or biometrics", async () => {
|
|
stateService.getAccountDecryptionOptions.mockResolvedValue(
|
|
new AccountDecryptionOptions({ hasMasterPassword: false }),
|
|
);
|
|
stateService.getPinKeyEncryptedUserKey.mockResolvedValue(null);
|
|
stateService.getProtectedPin.mockResolvedValue(null);
|
|
biometricStateService.biometricUnlockEnabled$ = of(false);
|
|
|
|
const result = await firstValueFrom(service.availableVaultTimeoutActions$());
|
|
|
|
expect(result).not.toContain(VaultTimeoutAction.Lock);
|
|
});
|
|
});
|
|
|
|
describe("vaultTimeoutAction$", () => {
|
|
describe("given the user has a master password", () => {
|
|
it.each`
|
|
policy | userPreference | expected
|
|
${null} | ${null} | ${VaultTimeoutAction.Lock}
|
|
${null} | ${VaultTimeoutAction.LogOut} | ${VaultTimeoutAction.LogOut}
|
|
${VaultTimeoutAction.LogOut} | ${null} | ${VaultTimeoutAction.LogOut}
|
|
${VaultTimeoutAction.LogOut} | ${VaultTimeoutAction.Lock} | ${VaultTimeoutAction.LogOut}
|
|
`(
|
|
"returns $expected when policy is $policy, and user preference is $userPreference",
|
|
async ({ policy, userPreference, expected }) => {
|
|
stateService.getAccountDecryptionOptions.mockResolvedValue(
|
|
new AccountDecryptionOptions({ hasMasterPassword: true }),
|
|
);
|
|
policyService.policyAppliesToUser.mockResolvedValue(policy === null ? false : true);
|
|
policyService.getAll.mockResolvedValue(
|
|
policy === null ? [] : ([{ data: { action: policy } }] as unknown as Policy[]),
|
|
);
|
|
stateService.getVaultTimeoutAction.mockResolvedValue(userPreference);
|
|
|
|
const result = await firstValueFrom(service.vaultTimeoutAction$());
|
|
|
|
expect(result).toBe(expected);
|
|
},
|
|
);
|
|
});
|
|
|
|
describe("given the user does not have a master password", () => {
|
|
it.each`
|
|
unlockMethod | policy | userPreference | expected
|
|
${false} | ${null} | ${null} | ${VaultTimeoutAction.LogOut}
|
|
${false} | ${null} | ${VaultTimeoutAction.Lock} | ${VaultTimeoutAction.LogOut}
|
|
${false} | ${VaultTimeoutAction.Lock} | ${null} | ${VaultTimeoutAction.LogOut}
|
|
${true} | ${null} | ${null} | ${VaultTimeoutAction.LogOut}
|
|
${true} | ${null} | ${VaultTimeoutAction.Lock} | ${VaultTimeoutAction.Lock}
|
|
${true} | ${VaultTimeoutAction.Lock} | ${null} | ${VaultTimeoutAction.Lock}
|
|
${true} | ${VaultTimeoutAction.Lock} | ${VaultTimeoutAction.LogOut} | ${VaultTimeoutAction.Lock}
|
|
`(
|
|
"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 }),
|
|
);
|
|
policyService.policyAppliesToUser.mockResolvedValue(policy === null ? false : true);
|
|
policyService.getAll.mockResolvedValue(
|
|
policy === null ? [] : ([{ data: { action: policy } }] as unknown as Policy[]),
|
|
);
|
|
stateService.getVaultTimeoutAction.mockResolvedValue(userPreference);
|
|
|
|
const result = await firstValueFrom(service.vaultTimeoutAction$());
|
|
|
|
expect(result).toBe(expected);
|
|
},
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
function createEncString() {
|
|
return Symbol() as unknown as EncString;
|
|
}
|