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

[AC-1045] add action to vault timeout policy (#4782)

This commit is contained in:
Jake Fink
2023-04-14 19:11:33 -04:00
committed by GitHub
parent 37230aa47f
commit fbbaf10488
23 changed files with 801 additions and 408 deletions

View File

@@ -1,6 +1,12 @@
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
export abstract class VaultTimeoutSettingsService {
setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise<void>;
setVaultTimeoutOptions: (
vaultTimeout: number,
vaultTimeoutAction: VaultTimeoutAction
) => Promise<void>;
getVaultTimeout: (userId?: string) => Promise<number>;
getVaultTimeoutAction: (userId?: string) => Promise<VaultTimeoutAction>;
isPinLockSet: () => Promise<[boolean, boolean]>;
isBiometricLockSet: () => Promise<boolean>;
clear: (userId?: string) => Promise<void>;

View File

@@ -10,6 +10,7 @@ import { PolicyResponse } from "../../models/response/policy.response";
export abstract class PolicyService {
policies$: Observable<Policy[]>;
get$: (policyType: PolicyType, policyFilter?: (policy: Policy) => boolean) => Observable<Policy>;
masterPasswordPolicyOptions$: (policies?: Policy[]) => Observable<MasterPasswordPolicyOptions>;
policyAppliesToActiveUser$: (
policyType: PolicyType,

View File

@@ -42,6 +42,28 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
.subscribe();
}
/**
* Returns the first policy found that applies to the active user
* @param policyType Policy type to search for
* @param policyFilter Additional filter to apply to the policy
*/
get$(policyType: PolicyType, policyFilter?: (policy: Policy) => boolean): Observable<Policy> {
return this.policies$.pipe(
concatMap(async (policies) => {
const userId = await this.stateService.getUserId();
const appliesToCurrentUser = await this.checkPoliciesThatApplyToUser(
policies,
policyType,
policyFilter,
userId
);
if (appliesToCurrentUser) {
return policies.find((policy) => policy.type === policyType && policy.enabled);
}
})
);
}
/**
* @deprecated Do not call this, use the policies$ observable collection
*/

View File

@@ -0,0 +1,4 @@
export enum VaultTimeoutAction {
Lock = "lock",
LogOut = "logOut",
}

View File

@@ -18,6 +18,7 @@ import { CollectionView } from "../admin-console/models/view/collection.view";
import { EnvironmentUrls } from "../auth/models/domain/environment-urls";
import { KdfConfig } from "../auth/models/domain/kdf-config";
import { HtmlStorageLocation, KdfType, StorageLocation, ThemeType, UriMatchType } from "../enums";
import { VaultTimeoutAction } from "../enums/vault-timeout-action.enum";
import { StateFactory } from "../factories/stateFactory";
import { Utils } from "../misc/utils";
import { EventData } from "../models/data/event.data";
@@ -2571,7 +2572,10 @@ export class StateService<
await this.storageService.remove(keys.tempAccountSettings);
}
account.settings.environmentUrls = environmentUrls;
if (account.settings.vaultTimeoutAction === "logOut" && account.settings.vaultTimeout != null) {
if (
account.settings.vaultTimeoutAction === VaultTimeoutAction.LogOut &&
account.settings.vaultTimeout != null
) {
account.tokens.accessToken = null;
account.tokens.refreshToken = null;
account.profile.apiKeyClientId = null;
@@ -2831,7 +2835,7 @@ export class StateService<
const timeoutAction = await this.getVaultTimeoutAction({ userId: options?.userId });
const timeout = await this.getVaultTimeout({ userId: options?.userId });
const defaultOptions =
timeoutAction === "logOut" && timeout != null
timeoutAction === VaultTimeoutAction.LogOut && timeout != null
? await this.defaultInMemoryOptions()
: await this.defaultOnDiskOptions();
return this.reconcileOptions(options, defaultOptions);

View File

@@ -11,6 +11,7 @@ import { CollectionService } from "../../admin-console/abstractions/collection.s
import { AuthService } from "../../auth/abstractions/auth.service";
import { KeyConnectorService } from "../../auth/abstractions/key-connector.service";
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
import { CipherService } from "../../vault/abstractions/cipher.service";
import { FolderService } from "../../vault/abstractions/folder/folder.service.abstraction";
@@ -132,7 +133,9 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}
private async executeTimeoutAction(userId: string): Promise<void> {
const timeoutAction = await this.stateService.getVaultTimeoutAction({ userId: userId });
timeoutAction === "logOut" ? await this.logOut(userId) : await this.lock(userId);
const timeoutAction = await this.vaultTimeoutSettingsService.getVaultTimeoutAction(userId);
timeoutAction === VaultTimeoutAction.LogOut
? await this.logOut(userId)
: await this.lock(userId);
}
}

View File

@@ -4,6 +4,7 @@ import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction }
import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "../../admin-console/enums";
import { TokenService } from "../../auth/abstractions/token.service";
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceAbstraction {
constructor(
@@ -13,7 +14,7 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
private stateService: StateService
) {}
async setVaultTimeoutOptions(timeout: number, action: string): Promise<void> {
async setVaultTimeoutOptions(timeout: number, action: VaultTimeoutAction): Promise<void> {
await this.stateService.setVaultTimeout(timeout);
// We swap these tokens from being on disk for lock actions, and in memory for logout actions
@@ -24,7 +25,11 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
const clientSecret = await this.tokenService.getClientSecret();
const currentAction = await this.stateService.getVaultTimeoutAction();
if ((timeout != null || timeout === 0) && action === "logOut" && action !== currentAction) {
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();
}
@@ -74,6 +79,29 @@ export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceA
return vaultTimeout;
}
async getVaultTimeoutAction(userId?: string): Promise<VaultTimeoutAction> {
let 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;
if (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 });
}
vaultTimeoutAction = action;
}
}
return vaultTimeoutAction === VaultTimeoutAction.LogOut
? VaultTimeoutAction.LogOut
: VaultTimeoutAction.Lock;
}
async clear(userId?: string): Promise<void> {
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
await this.stateService.setDecryptedPinProtected(null, { userId: userId });