diff --git a/common/src/abstractions/crypto.service.ts b/common/src/abstractions/crypto.service.ts index 9cc216f1..34d38108 100644 --- a/common/src/abstractions/crypto.service.ts +++ b/common/src/abstractions/crypto.service.ts @@ -29,7 +29,7 @@ export abstract class CryptoService { getOrgKey: (orgId: string) => Promise; getProviderKey: (providerId: string) => Promise; hasKey: () => Promise; - hasKeyInMemory: () => Promise; + hasKeyInMemory: (userId?: string) => Promise; hasKeyStored: (keySuffix?: KeySuffixOptions, userId?: string) => Promise; hasEncKey: () => Promise; clearKey: (clearSecretStorage?: boolean, userId?: string) => Promise; @@ -39,7 +39,7 @@ export abstract class CryptoService { clearOrgKeys: (memoryOnly?: boolean, userId?: string) => Promise; clearProviderKeys: (memoryOnly?: boolean) => Promise; clearPinProtectedKey: () => Promise; - clearKeys: () => Promise; + clearKeys: (userId?: string) => Promise; toggleKey: () => Promise; makeKey: (password: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise; makeKeyFromPin: (pin: string, salt: string, kdf: KdfType, kdfIterations: number, diff --git a/common/src/abstractions/event.service.ts b/common/src/abstractions/event.service.ts index 40c08027..ace10278 100644 --- a/common/src/abstractions/event.service.ts +++ b/common/src/abstractions/event.service.ts @@ -2,6 +2,6 @@ import { EventType } from '../enums/eventType'; export abstract class EventService { collect: (eventType: EventType, cipherId?: string, uploadImmediately?: boolean) => Promise; - uploadEvents: () => Promise; - clearEvents: () => Promise; + uploadEvents: (userId?: string) => Promise; + clearEvents: (userId?: string) => Promise; } diff --git a/common/src/abstractions/organization.service.ts b/common/src/abstractions/organization.service.ts index 1cde32f7..b129b4af 100644 --- a/common/src/abstractions/organization.service.ts +++ b/common/src/abstractions/organization.service.ts @@ -5,6 +5,6 @@ import { Organization } from '../models/domain/organization'; export abstract class OrganizationService { get: (id: string) => Promise; getByIdentifier: (identifier: string) => Promise; - getAll: () => Promise; + getAll: (userId?: string) => Promise; save: (orgs: {[id: string]: OrganizationData}) => Promise; } diff --git a/common/src/abstractions/passwordGeneration.service.ts b/common/src/abstractions/passwordGeneration.service.ts index 52d18dde..163e09c4 100644 --- a/common/src/abstractions/passwordGeneration.service.ts +++ b/common/src/abstractions/passwordGeneration.service.ts @@ -12,7 +12,7 @@ export abstract class PasswordGenerationService { saveOptions: (options: any) => Promise; getHistory: () => Promise; addHistory: (password: string) => Promise; - clear: () => Promise; + clear: (userId?: string) => Promise; passwordStrength: (password: string, userInputs?: string[]) => zxcvbn.ZXCVBNResult; normalizeOptions: (options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) => void; } diff --git a/common/src/abstractions/policy.service.ts b/common/src/abstractions/policy.service.ts index 6f9f6438..84ff94ac 100644 --- a/common/src/abstractions/policy.service.ts +++ b/common/src/abstractions/policy.service.ts @@ -11,14 +11,14 @@ import { PolicyType } from '../enums/policyType'; export abstract class PolicyService { clearCache: () => void; - getAll: (type?: PolicyType) => Promise; + getAll: (type?: PolicyType, userId?: string) => Promise; getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise; replace: (policies: { [id: string]: PolicyData; }) => Promise; - clear: (userId: string) => Promise; + clear: (userId?: string) => Promise; getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise; evaluateMasterPassword: (passwordStrength: number, newPassword: string, enforcedPolicyOptions?: MasterPasswordPolicyOptions) => boolean; getResetPasswordPolicyOptions: (policies: Policy[], orgId: string) => [ResetPasswordPolicyOptions, boolean]; mapPoliciesFromToken: (policiesResponse: ListResponse) => Policy[]; - policyAppliesToUser: (policyType: PolicyType, policyFilter?: (policy: Policy) => boolean) => Promise; + policyAppliesToUser: (policyType: PolicyType, policyFilter?: (policy: Policy) => boolean, userId?: string) => Promise; } diff --git a/common/src/abstractions/settings.service.ts b/common/src/abstractions/settings.service.ts index aa000d45..1112d557 100644 --- a/common/src/abstractions/settings.service.ts +++ b/common/src/abstractions/settings.service.ts @@ -2,5 +2,5 @@ export abstract class SettingsService { clearCache: () => Promise; getEquivalentDomains: () => Promise; setEquivalentDomains: (equivalentDomains: string[][]) => Promise; - clear: (userId: string) => Promise; + clear: (userId?: string) => Promise; } diff --git a/common/src/abstractions/sync.service.ts b/common/src/abstractions/sync.service.ts index 5d35cf20..31cb0d25 100644 --- a/common/src/abstractions/sync.service.ts +++ b/common/src/abstractions/sync.service.ts @@ -8,7 +8,7 @@ export abstract class SyncService { syncInProgress: boolean; getLastSync: () => Promise; - setLastSync: (date: Date) => Promise; + setLastSync: (date: Date, userId?: string) => Promise; fullSync: (forceSync: boolean, allowThrowOnError?: boolean) => Promise; syncUpsertFolder: (notification: SyncFolderNotification, isEdit: boolean) => Promise; syncDeleteFolder: (notification: SyncFolderNotification) => Promise; diff --git a/common/src/abstractions/token.service.ts b/common/src/abstractions/token.service.ts index 339b4a19..238a8c9a 100644 --- a/common/src/abstractions/token.service.ts +++ b/common/src/abstractions/token.service.ts @@ -12,7 +12,7 @@ export abstract class TokenService { setTwoFactorToken: (token: string, email: string) => Promise; getTwoFactorToken: (email: string) => Promise; clearTwoFactorToken: (email: string) => Promise; - clearToken: () => Promise; + clearToken: (userId?: string) => Promise; decodeToken: (token?: string) => any; getTokenExpirationDate: () => Promise; tokenSecondsRemaining: (offsetSeconds?: number) => Promise; diff --git a/common/src/abstractions/vaultTimeout.service.ts b/common/src/abstractions/vaultTimeout.service.ts index 3f365d05..0ac2ee86 100644 --- a/common/src/abstractions/vaultTimeout.service.ts +++ b/common/src/abstractions/vaultTimeout.service.ts @@ -2,10 +2,10 @@ export abstract class VaultTimeoutService { isLocked: (userId?: string) => Promise; checkVaultTimeout: () => Promise; lock: (allowSoftLock?: boolean, userId?: string) => Promise; - logOut: () => Promise; + logOut: (userId?: string) => Promise; setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise; getVaultTimeout: () => Promise; isPinLockSet: () => Promise<[boolean, boolean]>; isBiometricLockSet: () => Promise; - clear: () => Promise; + clear: (userId?: string) => Promise; } diff --git a/common/src/services/cipher.service.ts b/common/src/services/cipher.service.ts index 66758dbb..e0ace39c 100644 --- a/common/src/services/cipher.service.ts +++ b/common/src/services/cipher.service.ts @@ -709,9 +709,9 @@ export class CipherService implements CipherServiceAbstraction { await this.stateService.setEncryptedCiphers(ciphers); } - async clear(): Promise { - await this.clearEncryptedCiphersState(); - await this.clearCache(); + async clear(userId?: string): Promise { + await this.clearEncryptedCiphersState(userId); + await this.clearCache(userId); } async moveManyWithServer(ids: string[], folderId: string): Promise { @@ -1094,8 +1094,8 @@ export class CipherService implements CipherServiceAbstraction { } } - private async clearEncryptedCiphersState() { - await this.stateService.setEncryptedCiphers(null); + private async clearEncryptedCiphersState(userId?: string) { + await this.stateService.setEncryptedCiphers(null, { userId: userId }); } private async clearDecryptedCiphersState(userId?: string) { diff --git a/common/src/services/collection.service.ts b/common/src/services/collection.service.ts index 791e64bb..3affccd6 100644 --- a/common/src/services/collection.service.ts +++ b/common/src/services/collection.service.ts @@ -133,9 +133,9 @@ export class CollectionService implements CollectionServiceAbstraction { await this.stateService.setEncryptedCollections(collections); } - async clear(): Promise { - await this.clearCache(); - await this.stateService.setEncryptedCollections(null); + async clear(userId?: string): Promise { + await this.clearCache(userId); + await this.stateService.setEncryptedCollections(null, { userId: userId }); } async delete(id: string | string[]): Promise { diff --git a/common/src/services/crypto.service.ts b/common/src/services/crypto.service.ts index 5092fae7..7fecf7fa 100644 --- a/common/src/services/crypto.service.ts +++ b/common/src/services/crypto.service.ts @@ -328,8 +328,8 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.hasKeyInMemory() || await this.hasKeyStored(KeySuffixOptions.Auto) || await this.hasKeyStored(KeySuffixOptions.Biometric); } - async hasKeyInMemory(): Promise { - return await this.stateService.getCryptoMasterKey() != null; + async hasKeyInMemory(userId?: string): Promise { + return await this.stateService.getCryptoMasterKey({ userId: userId }) != null; } async hasKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise { diff --git a/common/src/services/event.service.ts b/common/src/services/event.service.ts index 44e6ce65..7f1de12a 100644 --- a/common/src/services/event.service.ts +++ b/common/src/services/event.service.ts @@ -64,12 +64,12 @@ export class EventService implements EventServiceAbstraction { } } - async uploadEvents(): Promise { - const authed = await this.stateService.getIsAuthenticated(); + async uploadEvents(userId?: string): Promise { + const authed = await this.stateService.getIsAuthenticated({ userId: userId }); if (!authed) { return; } - const eventCollection = await this.stateService.getEventCollection(); + const eventCollection = await this.stateService.getEventCollection({ userId: userId }); if (eventCollection == null || eventCollection.length === 0) { return; } @@ -82,13 +82,13 @@ export class EventService implements EventServiceAbstraction { }); try { await this.apiService.postEventsCollect(request); - this.clearEvents(); + this.clearEvents(userId); } catch (e) { this.logService.error(e); } } - async clearEvents(): Promise { - await this.stateService.setEventCollection(null); + async clearEvents(userId?: string): Promise { + await this.stateService.setEventCollection(null, { userId: userId }); } } diff --git a/common/src/services/folder.service.ts b/common/src/services/folder.service.ts index 0520db72..d8b95430 100644 --- a/common/src/services/folder.service.ts +++ b/common/src/services/folder.service.ts @@ -147,9 +147,9 @@ export class FolderService implements FolderServiceAbstraction { await this.stateService.setEncryptedFolders(folders); } - async clear(): Promise { - await this.stateService.setDecryptedFolders(null); - await this.stateService.setEncryptedFolders(null); + async clear(userId?: string): Promise { + await this.stateService.setDecryptedFolders(null, { userId: userId }); + await this.stateService.setEncryptedFolders(null, { userId: userId }); } async delete(id: string | string[]): Promise { diff --git a/common/src/services/organization.service.ts b/common/src/services/organization.service.ts index 5f9c0cee..faf676ea 100644 --- a/common/src/services/organization.service.ts +++ b/common/src/services/organization.service.ts @@ -27,8 +27,8 @@ export class OrganizationService implements OrganizationServiceAbstraction { return organizations.find(o => o.identifier === identifier); } - async getAll(): Promise { - const organizations = await this.stateService.getOrganizations(); + async getAll(userId?: string): Promise { + const organizations = await this.stateService.getOrganizations({ userId: userId }); const response: Organization[] = []; for (const id in organizations) { if (organizations.hasOwnProperty(id) && !organizations[id].isProviderUser) { diff --git a/common/src/services/passwordGeneration.service.ts b/common/src/services/passwordGeneration.service.ts index a93fb68d..c6d0d7cc 100644 --- a/common/src/services/passwordGeneration.service.ts +++ b/common/src/services/passwordGeneration.service.ts @@ -369,9 +369,9 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr return await this.stateService.setEncryptedPasswordGenerationHistory(newHistory); } - async clear(): Promise { - await this.stateService.setEncryptedPasswordGenerationHistory(null); - await this.stateService.setDecryptedPasswordGenerationHistory(null); + async clear(userId?: string): Promise { + await this.stateService.setEncryptedPasswordGenerationHistory(null, { userId: userId }); + await this.stateService.setDecryptedPasswordGenerationHistory(null, { userId: userId }); } passwordStrength(password: string, userInputs: string[] = null): zxcvbn.ZXCVBNResult { diff --git a/common/src/services/policy.service.ts b/common/src/services/policy.service.ts index f34781a4..042d01b0 100644 --- a/common/src/services/policy.service.ts +++ b/common/src/services/policy.service.ts @@ -28,19 +28,19 @@ export class PolicyService implements PolicyServiceAbstraction { await this.stateService.setDecryptedPolicies(null); } - async getAll(type?: PolicyType): Promise { + async getAll(type?: PolicyType, userId?: string): Promise { let response: Policy[] = []; - const decryptedPolicies = await this.stateService.getDecryptedPolicies(); + const decryptedPolicies = await this.stateService.getDecryptedPolicies({ userId: userId }); if (decryptedPolicies != null) { response = decryptedPolicies; } else { - const diskPolicies = await this.stateService.getEncryptedPolicies(); + const diskPolicies = await this.stateService.getEncryptedPolicies({ userId: userId }); for (const id in diskPolicies) { if (diskPolicies.hasOwnProperty(id)) { response.push(new Policy(diskPolicies[id])); } } - await this.stateService.setDecryptedPolicies(response); + await this.stateService.setDecryptedPolicies(response, { userId: userId }); } if (type != null) { return response.filter(policy => policy.type === type); @@ -71,9 +71,9 @@ export class PolicyService implements PolicyServiceAbstraction { await this.stateService.setEncryptedPolicies(policies); } - async clear(): Promise { - await this.stateService.setDecryptedPolicies(null); - await this.stateService.setEncryptedPolicies(null); + async clear(userId?: string): Promise { + await this.stateService.setDecryptedPolicies(null, { userId: userId }); + await this.stateService.setEncryptedPolicies(null, { userId: userId }); } async getMasterPasswordPolicyOptions(policies?: Policy[]): Promise { @@ -183,9 +183,9 @@ export class PolicyService implements PolicyServiceAbstraction { return policiesData.map(p => new Policy(p)); } - async policyAppliesToUser(policyType: PolicyType, policyFilter?: (policy: Policy) => boolean) { - const policies = await this.getAll(policyType); - const organizations = await this.organizationService.getAll(); + async policyAppliesToUser(policyType: PolicyType, policyFilter?: (policy: Policy) => boolean, userId?: string) { + const policies = await this.getAll(policyType, userId); + const organizations = await this.organizationService.getAll(userId); let filteredPolicies; if (policyFilter != null) { diff --git a/common/src/services/settings.service.ts b/common/src/services/settings.service.ts index 813e4c6f..38b32828 100644 --- a/common/src/services/settings.service.ts +++ b/common/src/services/settings.service.ts @@ -24,8 +24,8 @@ export class SettingsService implements SettingsServiceAbstraction { await this.setSettingsKey(Keys.equivalentDomains, equivalentDomains); } - async clear(): Promise { - await this.stateService.setSettings(null); + async clear(userId?: string): Promise { + await this.stateService.setSettings(null, { userId: userId }); } // Helpers diff --git a/common/src/services/sync.service.ts b/common/src/services/sync.service.ts index a97f62cc..945980be 100644 --- a/common/src/services/sync.service.ts +++ b/common/src/services/sync.service.ts @@ -59,12 +59,8 @@ export class SyncService implements SyncServiceAbstraction { return null; } - async setLastSync(date: Date): Promise { - if (await this.stateService.getUserId()) { - return; - } - - await this.stateService.setLastSync(date.toJSON()); + async setLastSync(date: Date, userId?: string): Promise { + await this.stateService.setLastSync(date.toJSON(), { userId: userId }); } async fullSync(forceSync: boolean, allowThrowOnError = false): Promise { diff --git a/common/src/services/token.service.ts b/common/src/services/token.service.ts index 8094f1e6..9336459a 100644 --- a/common/src/services/token.service.ts +++ b/common/src/services/token.service.ts @@ -93,11 +93,11 @@ export class TokenService implements TokenServiceAbstraction { return await this.stateService.setTwoFactorToken(null); } - async clearToken(): Promise { - await this.stateService.setAccessToken(null); - await this.stateService.setRefreshToken(null); - await this.stateService.setApiKeyClientId(null); - await this.stateService.setApiKeyClientSecret(null); + async clearToken(userId?: string): Promise { + await this.stateService.setAccessToken(null, { userId: userId }); + await this.stateService.setRefreshToken(null, { userId: userId }); + await this.stateService.setApiKeyClientId(null, { userId: userId }); + await this.stateService.setApiKeyClientSecret(null, { userId: userId }); } // jwthelper methods diff --git a/common/src/services/vaultTimeout.service.ts b/common/src/services/vaultTimeout.service.ts index 0d8c63bc..bf6d7246 100644 --- a/common/src/services/vaultTimeout.service.ts +++ b/common/src/services/vaultTimeout.service.ts @@ -12,8 +12,6 @@ import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from '../abstra import { KeySuffixOptions } from '../enums/keySuffixOptions'; import { PolicyType } from '../enums/policyType'; -import { StorageLocation } from '../enums/storageLocation'; - export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { private inited = false; @@ -23,7 +21,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { protected platformUtilsService: PlatformUtilsService, private messagingService: MessagingService, private searchService: SearchService, private tokenService: TokenService, private policyService: PolicyService, private stateService: StateService, - private lockedCallback: () => Promise = null, private loggedOutCallback: () => Promise = null) { + private lockedCallback: () => Promise = null, private loggedOutCallback: (userId?: string) => Promise = null) { } init(checkOnInterval: boolean) { @@ -50,7 +48,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { return (await this.cryptoService.getKey(KeySuffixOptions.Auto, userId)) != null; } - return !(await this.cryptoService.hasKeyInMemory()); + return !(await this.cryptoService.hasKeyInMemory(userId)); } async checkVaultTimeout(): Promise { @@ -59,32 +57,34 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { return; } - // "is logged out check" - similar to isLocked, below - const authed = await this.stateService.getIsAuthenticated(); - if (!authed) { - return; - } + for (const userId in this.stateService.accounts.getValue()) { + if (userId != null) { + if (await this.isLoggedOut(userId)) { + return; + } - if (await this.isLocked()) { - return; - } + if (await this.isLocked(userId)) { + return; + } - const vaultTimeout = await this.getVaultTimeout(); - if (vaultTimeout == null || vaultTimeout < 0) { - return; - } + const vaultTimeout = await this.getVaultTimeout(userId); + if (vaultTimeout == null || vaultTimeout < 0) { + return; + } - const lastActive = await this.stateService.getLastActive(); - if (lastActive == null) { - return; - } + const lastActive = await this.stateService.getLastActive({ userId: userId }); + if (lastActive == null) { + return; + } - const vaultTimeoutSeconds = vaultTimeout * 60; - const diffSeconds = ((new Date()).getTime() - lastActive) / 1000; - if (diffSeconds >= vaultTimeoutSeconds) { - // Pivot based on the saved vault timeout action - const timeoutAction = await this.stateService.getVaultTimeoutAction(); - timeoutAction === 'logOut' ? await this.logOut() : await this.lock(true); + const vaultTimeoutSeconds = vaultTimeout * 60; + const diffSeconds = ((new Date()).getTime() - lastActive) / 1000; + if (diffSeconds >= vaultTimeoutSeconds) { + // Pivot based on the saved vault timeout action + const timeoutAction = await this.stateService.getVaultTimeoutAction({ userId: userId }); + timeoutAction === 'logOut' ? await this.logOut() : await this.lock(true, userId); + } + } } } @@ -114,9 +114,9 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { } } - async logOut(): Promise { + async logOut(userId?: string): Promise { if (this.loggedOutCallback != null) { - await this.loggedOutCallback(); + await this.loggedOutCallback(userId); } } @@ -137,11 +137,11 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { return await this.stateService.getBiometricUnlock(); } - async getVaultTimeout(): Promise { - const vaultTimeout = await this.stateService.getVaultTimeout(); + async getVaultTimeout(userId?: string): Promise { + const vaultTimeout = await this.stateService.getVaultTimeout( { userId: userId } ); - if (await this.policyService.policyAppliesToUser(PolicyType.MaximumVaultTimeout)) { - const policy = await this.policyService.getAll(PolicyType.MaximumVaultTimeout); + 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); @@ -151,7 +151,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { // 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); + await this.stateService.setVaultTimeout(timeout, { userId: userId }); } return timeout; @@ -160,9 +160,13 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { return vaultTimeout; } - async clear(): Promise { - await this.stateService.setEverBeenUnlocked(false); - await this.stateService.setDecryptedPinProtected(null); - await this.stateService.setProtectedPin(null); + async clear(userId?: string): Promise { + await this.stateService.setEverBeenUnlocked(false, { userId: userId }); + await this.stateService.setDecryptedPinProtected(null, { userId: userId }); + await this.stateService.setProtectedPin(null, { userId: userId }); + } + + private async isLoggedOut(userId?: string): Promise { + return !(await this.stateService.getIsAuthenticated({ userId: userId })); } }