1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

Extract settings related methods into VaultTimeoutSettingsService (#3419)

* Extract into new VaultTimeoutSettingsService

* Ensure new service is instantiated and registered for DI

* Create vaultTimeoutSettingsServiceFactory

* Fix VaultTimeoutServiceFactory

* Remove any and use void instead
This commit is contained in:
Daniel James Smith
2022-08-30 22:30:43 +02:00
committed by GitHub
parent 595412c5fe
commit 25207c2858
18 changed files with 214 additions and 113 deletions

View File

@@ -13,6 +13,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
import { HashPurpose } from "@bitwarden/common/enums/hashPurpose";
import { KeySuffixOptions } from "@bitwarden/common/enums/keySuffixOptions";
import { Utils } from "@bitwarden/common/misc/utils";
@@ -49,6 +50,7 @@ export class LockComponent implements OnInit, OnDestroy {
protected messagingService: MessagingService,
protected cryptoService: CryptoService,
protected vaultTimeoutService: VaultTimeoutService,
protected vaultTimeoutSettingsService: VaultTimeoutSettingsService,
protected environmentService: EnvironmentService,
protected stateService: StateService,
protected apiService: ApiService,
@@ -262,13 +264,13 @@ export class LockComponent implements OnInit, OnDestroy {
}
private async load() {
this.pinSet = await this.vaultTimeoutService.isPinLockSet();
this.pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
this.pinLock =
(this.pinSet[0] && (await this.stateService.getDecryptedPinProtected()) != null) ||
this.pinSet[1];
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
this.biometricLock =
(await this.vaultTimeoutService.isBiometricLockSet()) &&
(await this.vaultTimeoutSettingsService.isBiometricLockSet()) &&
((await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric)) ||
!this.platformUtilsService.supportsSecureStorage());
this.biometricText = await this.stateService.getBiometricText();

View File

@@ -54,6 +54,7 @@ import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstrac
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
import { Account } from "@bitwarden/common/models/domain/account";
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
@@ -96,6 +97,7 @@ import { UserVerificationApiService } from "@bitwarden/common/services/userVerif
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout/vaultTimeout.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service";
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
import { AuthGuard } from "../guards/auth.guard";
@@ -344,6 +346,16 @@ export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
useClass: SettingsService,
deps: [StateServiceAbstraction],
},
{
provide: VaultTimeoutSettingsServiceAbstraction,
useClass: VaultTimeoutSettingsService,
deps: [
CryptoServiceAbstraction,
TokenServiceAbstraction,
PolicyServiceAbstraction,
StateServiceAbstraction,
],
},
{
provide: VaultTimeoutServiceAbstraction,
useClass: VaultTimeoutService,
@@ -355,11 +367,10 @@ export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
PlatformUtilsServiceAbstraction,
MessagingServiceAbstraction,
SearchServiceAbstraction,
TokenServiceAbstraction,
PolicyServiceAbstraction,
KeyConnectorServiceAbstraction,
StateServiceAbstraction,
AuthServiceAbstraction,
VaultTimeoutSettingsServiceAbstraction,
LOCKED_CALLBACK,
LOGOUT_CALLBACK,
],

View File

@@ -2,9 +2,4 @@ export abstract class VaultTimeoutService {
checkVaultTimeout: () => Promise<void>;
lock: (userId?: string) => Promise<void>;
logOut: (userId?: string) => Promise<void>;
setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise<void>;
getVaultTimeout: () => Promise<number>;
isPinLockSet: () => Promise<[boolean, boolean]>;
isBiometricLockSet: () => Promise<boolean>;
clear: (userId?: string) => Promise<any>;
}

View File

@@ -0,0 +1,7 @@
export abstract class VaultTimeoutSettingsService {
setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise<void>;
getVaultTimeout: (userId?: string) => Promise<number>;
isPinLockSet: () => Promise<[boolean, boolean]>;
isBiometricLockSet: () => Promise<boolean>;
clear: (userId?: string) => Promise<void>;
}

View File

@@ -6,13 +6,11 @@ import { FolderService } from "../../abstractions/folder/folder.service.abstract
import { KeyConnectorService } from "../../abstractions/keyConnector.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { PolicyService } from "../../abstractions/policy/policy.service.abstraction";
import { SearchService } from "../../abstractions/search.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vaultTimeout/vaultTimeout.service";
import { VaultTimeoutSettingsService } from "../../abstractions/vaultTimeout/vaultTimeoutSettings.service";
import { AuthenticationStatus } from "../../enums/authenticationStatus";
import { PolicyType } from "../../enums/policyType";
export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
private inited = false;
@@ -25,11 +23,10 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
protected platformUtilsService: PlatformUtilsService,
private messagingService: MessagingService,
private searchService: SearchService,
private tokenService: TokenService,
private policyService: PolicyService,
private keyConnectorService: KeyConnectorService,
private stateService: StateService,
private authService: AuthService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
private lockedCallback: (userId?: string) => Promise<void> = null,
private loggedOutCallback: (expired: boolean, userId?: string) => Promise<void> = null
) {}
@@ -69,11 +66,11 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}
if (await this.keyConnectorService.getUsesKeyConnector()) {
const pinSet = await this.isPinLockSet();
const pinSet = await this.vaultTimeoutSettingsService.isPinLockSet();
const pinLock =
(pinSet[0] && (await this.stateService.getDecryptedPinProtected()) != null) || pinSet[1];
if (!pinLock && !(await this.isBiometricLockSet())) {
if (!pinLock && !(await this.vaultTimeoutSettingsService.isBiometricLockSet())) {
await this.logOut(userId);
}
}
@@ -107,73 +104,6 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}
}
async setVaultTimeoutOptions(timeout: number, action: string): Promise<void> {
await this.stateService.setVaultTimeout(timeout);
// 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();
const currentAction = await this.stateService.getVaultTimeoutAction();
if ((timeout != null || timeout === 0) && action === "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.toggleKey();
}
async isPinLockSet(): Promise<[boolean, boolean]> {
const protectedPin = await this.stateService.getProtectedPin();
const pinProtectedKey = await this.stateService.getEncryptedPinProtected();
return [protectedPin != null, pinProtectedKey != null];
}
async isBiometricLockSet(): Promise<boolean> {
return await this.stateService.getBiometricUnlock();
}
async getVaultTimeout(userId?: string): Promise<number> {
const vaultTimeout = await this.stateService.getVaultTimeout({ userId: 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;
}
// 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: userId });
}
return timeout;
}
return vaultTimeout;
}
async clear(userId?: string): Promise<void> {
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
await this.stateService.setDecryptedPinProtected(null, { userId: userId });
await this.stateService.setProtectedPin(null, { userId: userId });
}
private async shouldLock(userId: string): Promise<boolean> {
const authStatus = await this.authService.getAuthStatus(userId);
if (
@@ -183,7 +113,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
return false;
}
const vaultTimeout = await this.getVaultTimeout(userId);
const vaultTimeout = await this.vaultTimeoutSettingsService.getVaultTimeout(userId);
if (vaultTimeout == null || vaultTimeout < 0) {
return false;
}

View File

@@ -0,0 +1,82 @@
import { CryptoService } from "../../abstractions/crypto.service";
import { PolicyService } from "../../abstractions/policy/policy.service.abstraction";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "../../abstractions/vaultTimeout/vaultTimeoutSettings.service";
import { PolicyType } from "../../enums/policyType";
export class VaultTimeoutSettingsService implements VaultTimeoutSettingsServiceAbstraction {
constructor(
private cryptoService: CryptoService,
private tokenService: TokenService,
private policyService: PolicyService,
private stateService: StateService
) {}
async setVaultTimeoutOptions(timeout: number, action: string): Promise<void> {
await this.stateService.setVaultTimeout(timeout);
// 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();
const currentAction = await this.stateService.getVaultTimeoutAction();
if ((timeout != null || timeout === 0) && action === "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.toggleKey();
}
async isPinLockSet(): Promise<[boolean, boolean]> {
const protectedPin = await this.stateService.getProtectedPin();
const pinProtectedKey = await this.stateService.getEncryptedPinProtected();
return [protectedPin != null, pinProtectedKey != null];
}
async isBiometricLockSet(): Promise<boolean> {
return await this.stateService.getBiometricUnlock();
}
async getVaultTimeout(userId?: string): Promise<number> {
const vaultTimeout = await this.stateService.getVaultTimeout({ userId: 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;
}
// 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: userId });
}
return timeout;
}
return vaultTimeout;
}
async clear(userId?: string): Promise<void> {
await this.stateService.setEverBeenUnlocked(false, { userId: userId });
await this.stateService.setDecryptedPinProtected(null, { userId: userId });
await this.stateService.setProtectedPin(null, { userId: userId });
}
}