mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 01:03:35 +00:00
* [deps] Autofill: Update prettier to v3 * prettier formatting updates --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jonathan Prusik <jprusik@classynemesis.com>
170 lines
6.8 KiB
TypeScript
170 lines
6.8 KiB
TypeScript
import { defer } from "rxjs";
|
|
|
|
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";
|
|
import { TokenService } from "../../auth/abstractions/token.service";
|
|
import { UserVerificationService } from "../../auth/abstractions/user-verification/user-verification.service.abstraction";
|
|
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
|
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
|
import { StateService } from "../../platform/abstractions/state.service";
|
|
|
|
/**
|
|
* - DISABLED: No Pin set
|
|
* - PERSISTENT: Pin is set and survives client reset
|
|
* - TRANSIENT: Pin is set and requires password unlock after client reset
|
|
*/
|
|
export type PinLockType = "DISABLED" | "PERSISTANT" | "TRANSIENT";
|
|
|
|
export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceAbstraction {
|
|
constructor(
|
|
private cryptoService: CryptoService,
|
|
private tokenService: TokenService,
|
|
private policyService: PolicyService,
|
|
private stateService: StateService,
|
|
private userVerificationService: UserVerificationService,
|
|
) {}
|
|
|
|
async setVaultTimeoutOptions(timeout: number, action: VaultTimeoutAction): Promise<void> {
|
|
// We swap these tokens from being on disk for lock actions, and in memory for logout actions
|
|
// Get them here to set them to their new location after changing the timeout action and clearing if needed
|
|
const token = await this.tokenService.getToken();
|
|
const refreshToken = await this.tokenService.getRefreshToken();
|
|
const clientId = await this.tokenService.getClientId();
|
|
const clientSecret = await this.tokenService.getClientSecret();
|
|
|
|
await this.stateService.setVaultTimeout(timeout);
|
|
|
|
const currentAction = await this.stateService.getVaultTimeoutAction();
|
|
if (
|
|
(timeout != null || timeout === 0) &&
|
|
action === VaultTimeoutAction.LogOut &&
|
|
action !== currentAction
|
|
) {
|
|
// if we have a vault timeout and the action is log out, reset tokens
|
|
await this.tokenService.clearToken();
|
|
}
|
|
|
|
await this.stateService.setVaultTimeoutAction(action);
|
|
|
|
await this.tokenService.setToken(token);
|
|
await this.tokenService.setRefreshToken(refreshToken);
|
|
await this.tokenService.setClientId(clientId);
|
|
await this.tokenService.setClientSecret(clientSecret);
|
|
|
|
await this.cryptoService.refreshAdditionalKeys();
|
|
}
|
|
|
|
availableVaultTimeoutActions$(userId?: string) {
|
|
return defer(() => this.getAvailableVaultTimeoutActions(userId));
|
|
}
|
|
|
|
async isPinLockSet(userId?: string): Promise<PinLockType> {
|
|
// we can't check the protected pin for both because old accounts only
|
|
// used it for MP on Restart
|
|
const pinIsEnabled = !!(await this.stateService.getProtectedPin({ userId }));
|
|
const aUserKeyPinIsSet = !!(await this.stateService.getPinKeyEncryptedUserKey({ userId }));
|
|
const anOldUserKeyPinIsSet = !!(await this.stateService.getEncryptedPinProtected({ userId }));
|
|
|
|
if (aUserKeyPinIsSet || anOldUserKeyPinIsSet) {
|
|
return "PERSISTANT";
|
|
} else if (pinIsEnabled && !aUserKeyPinIsSet && !anOldUserKeyPinIsSet) {
|
|
return "TRANSIENT";
|
|
} else {
|
|
return "DISABLED";
|
|
}
|
|
}
|
|
|
|
async isBiometricLockSet(userId?: string): Promise<boolean> {
|
|
return await this.stateService.getBiometricUnlock({ userId });
|
|
}
|
|
|
|
async getVaultTimeout(userId?: string): Promise<number> {
|
|
const vaultTimeout = await this.stateService.getVaultTimeout({ userId });
|
|
|
|
if (
|
|
await this.policyService.policyAppliesToUser(PolicyType.MaximumVaultTimeout, null, userId)
|
|
) {
|
|
const policy = await this.policyService.getAll(PolicyType.MaximumVaultTimeout, userId);
|
|
// Remove negative values, and ensure it's smaller than maximum allowed value according to policy
|
|
let timeout = Math.min(vaultTimeout, policy[0].data.minutes);
|
|
|
|
if (vaultTimeout == null || timeout < 0) {
|
|
timeout = policy[0].data.minutes;
|
|
}
|
|
|
|
// TODO @jlf0dev: Can we move this somwhere else? Maybe add it to the initialization process?
|
|
// ( Apparently I'm the one that reviewed the original PR that added this :) )
|
|
// We really shouldn't need to set the value here, but multiple services relies on this value being correct.
|
|
if (vaultTimeout !== timeout) {
|
|
await this.stateService.setVaultTimeout(timeout, { userId });
|
|
}
|
|
|
|
return timeout;
|
|
}
|
|
|
|
return vaultTimeout;
|
|
}
|
|
|
|
vaultTimeoutAction$(userId?: string) {
|
|
return defer(() => this.getVaultTimeoutAction(userId));
|
|
}
|
|
|
|
async getVaultTimeoutAction(userId?: string): Promise<VaultTimeoutAction> {
|
|
const availableActions = await this.getAvailableVaultTimeoutActions();
|
|
if (availableActions.length === 1) {
|
|
return availableActions[0];
|
|
}
|
|
|
|
const vaultTimeoutAction = await this.stateService.getVaultTimeoutAction({ userId: userId });
|
|
|
|
if (
|
|
await this.policyService.policyAppliesToUser(PolicyType.MaximumVaultTimeout, null, userId)
|
|
) {
|
|
const policy = await this.policyService.getAll(PolicyType.MaximumVaultTimeout, userId);
|
|
const action = policy[0].data.action;
|
|
// We really shouldn't need to set the value here, but multiple services relies on this value being correct.
|
|
if (action && vaultTimeoutAction !== action) {
|
|
await this.stateService.setVaultTimeoutAction(action, { userId: userId });
|
|
}
|
|
if (action && availableActions.includes(action)) {
|
|
return action;
|
|
}
|
|
}
|
|
|
|
if (vaultTimeoutAction == null) {
|
|
// Depends on whether or not the user has a master password
|
|
const defaultValue = (await this.userVerificationService.hasMasterPassword())
|
|
? VaultTimeoutAction.Lock
|
|
: VaultTimeoutAction.LogOut;
|
|
// We really shouldn't need to set the value here, but multiple services relies on this value being correct.
|
|
await this.stateService.setVaultTimeoutAction(defaultValue, { userId: userId });
|
|
return defaultValue;
|
|
}
|
|
|
|
return vaultTimeoutAction === VaultTimeoutAction.LogOut
|
|
? VaultTimeoutAction.LogOut
|
|
: VaultTimeoutAction.Lock;
|
|
}
|
|
|
|
private async getAvailableVaultTimeoutActions(userId?: string): Promise<VaultTimeoutAction[]> {
|
|
const availableActions = [VaultTimeoutAction.LogOut];
|
|
|
|
const canLock =
|
|
(await this.userVerificationService.hasMasterPassword(userId)) ||
|
|
(await this.isPinLockSet(userId)) !== "DISABLED" ||
|
|
(await this.isBiometricLockSet(userId));
|
|
|
|
if (canLock) {
|
|
availableActions.push(VaultTimeoutAction.Lock);
|
|
}
|
|
|
|
return availableActions;
|
|
}
|
|
|
|
async clear(userId?: string): Promise<void> {
|
|
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
|
|
await this.cryptoService.clearPinKeys(userId);
|
|
}
|
|
}
|