diff --git a/common/src/abstractions/cipher.service.ts b/common/src/abstractions/cipher.service.ts index 0b7934ab..d8db4a62 100644 --- a/common/src/abstractions/cipher.service.ts +++ b/common/src/abstractions/cipher.service.ts @@ -11,7 +11,7 @@ import { CipherView } from '../models/view/cipherView'; import { FieldView } from '../models/view/fieldView'; export abstract class CipherService { - clearCache: () => Promise; + clearCache: (userId?: string) => Promise; encrypt: (model: CipherView, key?: SymmetricCryptoKey, originalCipher?: Cipher) => Promise; encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise; encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise; diff --git a/common/src/abstractions/collection.service.ts b/common/src/abstractions/collection.service.ts index b630f209..987fcdd0 100644 --- a/common/src/abstractions/collection.service.ts +++ b/common/src/abstractions/collection.service.ts @@ -6,7 +6,7 @@ import { TreeNode } from '../models/domain/treeNode'; import { CollectionView } from '../models/view/collectionView'; export abstract class CollectionService { - clearCache: () => Promise; + clearCache: (userId?: string) => Promise; encrypt: (model: CollectionView) => Promise; decryptMany: (collections: Collection[]) => Promise; get: (id: string) => Promise; diff --git a/common/src/abstractions/crypto.service.ts b/common/src/abstractions/crypto.service.ts index e85b9922..9cc216f1 100644 --- a/common/src/abstractions/crypto.service.ts +++ b/common/src/abstractions/crypto.service.ts @@ -17,7 +17,7 @@ export abstract class CryptoService { setEncPrivateKey: (encPrivateKey: string) => Promise; setOrgKeys: (orgs: ProfileOrganizationResponse[], providerOrgs: ProfileProviderOrganizationResponse[]) => Promise; setProviderKeys: (orgs: ProfileProviderResponse[]) => Promise; - getKey: (keySuffix?: KeySuffixOptions) => Promise; + getKey: (keySuffix?: KeySuffixOptions, userId?: string) => Promise; getKeyFromStorage: (keySuffix: KeySuffixOptions) => Promise; getKeyHash: () => Promise; compareAndUpdateKeyHash: (masterPassword: string, key: SymmetricCryptoKey) => Promise; @@ -30,13 +30,13 @@ export abstract class CryptoService { getProviderKey: (providerId: string) => Promise; hasKey: () => Promise; hasKeyInMemory: () => Promise; - hasKeyStored: (keySuffix?: KeySuffixOptions) => Promise; + hasKeyStored: (keySuffix?: KeySuffixOptions, userId?: string) => Promise; hasEncKey: () => Promise; - clearKey: (clearSecretStorage?: boolean) => Promise; + clearKey: (clearSecretStorage?: boolean, userId?: string) => Promise; clearKeyHash: () => Promise; - clearEncKey: (memoryOnly?: boolean) => Promise; - clearKeyPair: (memoryOnly?: boolean) => Promise; - clearOrgKeys: (memoryOnly?: boolean) => Promise; + clearEncKey: (memoryOnly?: boolean, userId?: string) => Promise; + clearKeyPair: (memoryOnly?: boolean, userId?: string) => Promise; + clearOrgKeys: (memoryOnly?: boolean, userId?: string) => Promise; clearProviderKeys: (memoryOnly?: boolean) => Promise; clearPinProtectedKey: () => Promise; clearKeys: () => Promise; diff --git a/common/src/abstractions/folder.service.ts b/common/src/abstractions/folder.service.ts index b676b421..339aec89 100644 --- a/common/src/abstractions/folder.service.ts +++ b/common/src/abstractions/folder.service.ts @@ -7,7 +7,7 @@ import { TreeNode } from '../models/domain/treeNode'; import { FolderView } from '../models/view/folderView'; export abstract class FolderService { - clearCache: () => Promise; + clearCache: (userId?: string) => Promise; encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise; get: (id: string) => Promise; getAll: () => Promise; diff --git a/common/src/abstractions/vaultTimeout.service.ts b/common/src/abstractions/vaultTimeout.service.ts index b20d1a17..3f365d05 100644 --- a/common/src/abstractions/vaultTimeout.service.ts +++ b/common/src/abstractions/vaultTimeout.service.ts @@ -1,7 +1,7 @@ export abstract class VaultTimeoutService { - isLocked: () => Promise; + isLocked: (userId?: string) => Promise; checkVaultTimeout: () => Promise; - lock: (allowSoftLock?: boolean) => Promise; + lock: (allowSoftLock?: boolean, userId?: string) => Promise; logOut: () => Promise; setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise; getVaultTimeout: () => Promise; diff --git a/common/src/services/cipher.service.ts b/common/src/services/cipher.service.ts index 7b9729dd..15523b80 100644 --- a/common/src/services/cipher.service.ts +++ b/common/src/services/cipher.service.ts @@ -81,8 +81,8 @@ export class CipherService implements CipherServiceAbstraction { } } - async clearCache(): Promise { - await this.clearDecryptedCiphersState(); + async clearCache(userId?: string): Promise { + await this.clearDecryptedCiphersState(userId); } async encrypt(model: CipherView, key?: SymmetricCryptoKey, originalCipher: Cipher = null): Promise { @@ -1098,8 +1098,8 @@ export class CipherService implements CipherServiceAbstraction { await this.stateService.setEncryptedCiphers(null); } - private async clearDecryptedCiphersState() { - await this.stateService.setDecryptedCiphers(null); + private async clearDecryptedCiphersState(userId?: string) { + await this.stateService.setDecryptedCiphers(null, { userId }); this.clearSortedCiphers(); } diff --git a/common/src/services/collection.service.ts b/common/src/services/collection.service.ts index ba3933d2..89c3efec 100644 --- a/common/src/services/collection.service.ts +++ b/common/src/services/collection.service.ts @@ -20,8 +20,8 @@ export class CollectionService implements CollectionServiceAbstraction { private stateService: StateService) { } - async clearCache(): Promise { - await this.stateService.setDecryptedCollections(null); + async clearCache(userId?: string): Promise { + await this.stateService.setDecryptedCollections(null, { userId }); } async encrypt(model: CollectionView): Promise { diff --git a/common/src/services/crypto.service.ts b/common/src/services/crypto.service.ts index ab74f9f1..c0969192 100644 --- a/common/src/services/crypto.service.ts +++ b/common/src/services/crypto.service.ts @@ -30,11 +30,14 @@ export class CryptoService implements CryptoServiceAbstraction { protected logService: LogService, protected stateService: StateService) { } - async setKey(key: SymmetricCryptoKey): Promise { - await this.stateService.setCryptoMasterKey(key); + async setKey(key: SymmetricCryptoKey, userId?: string): Promise { + const storageOptions = userId ? + { userId, storageLocation: StorageLocation.Memory } : + null; + await this.stateService.setCryptoMasterKey(key, storageOptions); const suffix = await this.getSuffix(); if (suffix != null) { - await this.stateService.setCryptoMasterKeyB64(key.keyB64, { keySuffix: suffix }); + await this.stateService.setCryptoMasterKeyB64(key.keyB64, { keySuffix: suffix, userId }); } else { await this.clearSecretKeyStore(); } @@ -89,30 +92,34 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.stateService.setEncryptedProviderKeys(providerKeys); } - async getKey(keySuffix?: KeySuffixOptions): Promise { - const inMemoryKey = await this.stateService.getCryptoMasterKey(); + async getKey(keySuffix?: KeySuffixOptions, userId?: string): Promise { + const inMemoryKey = await this.stateService.getCryptoMasterKey( + userId ? { userId } : + null + ); + if (inMemoryKey != null) { return inMemoryKey; } keySuffix ||= KeySuffixOptions.Auto; - const symmetricKey = await this.getKeyFromStorage(keySuffix); + const symmetricKey = await this.getKeyFromStorage(keySuffix, userId); if (symmetricKey != null) { - this.setKey(symmetricKey); + this.setKey(symmetricKey, userId); } return symmetricKey; } - async getKeyFromStorage(keySuffix: KeySuffixOptions): Promise { - const key = await this.retrieveKeyFromStorage(keySuffix); + async getKeyFromStorage(keySuffix: KeySuffixOptions, userId?: string): Promise { + const key = await this.retrieveKeyFromStorage(keySuffix, userId); if (key != null) { const symmetricKey = new SymmetricCryptoKey(Utils.fromB64ToArray(key).buffer); if (!await this.validateKey(symmetricKey)) { this.logService.warning('Wrong key, throwing away stored key'); - await this.clearSecretKeyStore(); + await this.clearSecretKeyStore(userId); return null; } @@ -333,19 +340,19 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.stateService.getCryptoMasterKey() != null; } - async hasKeyStored(keySuffix: KeySuffixOptions): Promise { - return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix }) != null; + async hasKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise { + return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix, userId }) != null; } async hasEncKey(): Promise { return await this.stateService.getDecryptedCryptoSymmetricKey() != null; } - async clearKey(clearSecretStorage: boolean = true): Promise { - await this.stateService.setCryptoMasterKey(null); - await this.stateService.setLegacyEtmKey(null); + async clearKey(clearSecretStorage: boolean = true, userId?: string): Promise { + await this.stateService.setCryptoMasterKey(null, { userId }); + await this.stateService.setLegacyEtmKey(null, { userId }); if (clearSecretStorage) { - await this.clearSecretKeyStore(); + await this.clearSecretKeyStore(userId); } } @@ -357,28 +364,28 @@ export class CryptoService implements CryptoServiceAbstraction { return await this.stateService.setKeyHash(null); } - async clearEncKey(memoryOnly?: boolean): Promise { - await this.stateService.setDecryptedCryptoSymmetricKey(null); + async clearEncKey(memoryOnly?: boolean, userId?: string): Promise { + await this.stateService.setDecryptedCryptoSymmetricKey(null, { userId }); if (!memoryOnly) { - await this.stateService.setEncryptedCryptoSymmetricKey(null); + await this.stateService.setEncryptedCryptoSymmetricKey(null, { userId }); } } - async clearKeyPair(memoryOnly?: boolean): Promise { + async clearKeyPair(memoryOnly?: boolean, userId?: string): Promise { const keysToClear: Promise[] = [ - this.stateService.setDecryptedPrivateKey(null), - this.stateService.setPublicKey(null), + this.stateService.setDecryptedPrivateKey(null, { userId }), + this.stateService.setPublicKey(null, { userId }), ]; if (!memoryOnly) { - keysToClear.push(this.stateService.setEncryptedPrivateKey(null)); + keysToClear.push(this.stateService.setEncryptedPrivateKey(null, { userId })); } return Promise.all(keysToClear); } - async clearOrgKeys(memoryOnly?: boolean): Promise { - await this.stateService.setDecryptedOrganizationKeys(null); + async clearOrgKeys(memoryOnly?: boolean, userId?: string): Promise { + await this.stateService.setDecryptedOrganizationKeys(null, { userId }); if (!memoryOnly) { - await this.stateService.setEncryptedOrganizationKeys(null); + await this.stateService.setEncryptedOrganizationKeys(null, { userId }); } } @@ -716,8 +723,8 @@ export class CryptoService implements CryptoServiceAbstraction { return shouldStoreKey; } - protected async retrieveKeyFromStorage(keySuffix: KeySuffixOptions) { - return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix }); + protected async retrieveKeyFromStorage(keySuffix: KeySuffixOptions, userId?: string) { + return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix, userId }); } private async aesEncrypt(data: ArrayBuffer, key: SymmetricCryptoKey): Promise { @@ -876,8 +883,8 @@ export class CryptoService implements CryptoServiceAbstraction { null; } - private async clearSecretKeyStore(): Promise { - await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Auto }); - await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Biometric }); + private async clearSecretKeyStore(userId?: string): Promise { + await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Auto, userId }); + await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Biometric, userId }); } } diff --git a/common/src/services/folder.service.ts b/common/src/services/folder.service.ts index 620cab93..1615dc9e 100644 --- a/common/src/services/folder.service.ts +++ b/common/src/services/folder.service.ts @@ -29,8 +29,8 @@ export class FolderService implements FolderServiceAbstraction { private i18nService: I18nService, private cipherService: CipherService, private stateService: StateService) { } - async clearCache(): Promise { - await this.stateService.setDecryptedFolders(null); + async clearCache(userId?: string): Promise { + await this.stateService.setDecryptedFolders(null, { userId }); } async encrypt(model: FolderView, key?: SymmetricCryptoKey): Promise { diff --git a/common/src/services/vaultTimeout.service.ts b/common/src/services/vaultTimeout.service.ts index 57acb9f8..1e9d9eff 100644 --- a/common/src/services/vaultTimeout.service.ts +++ b/common/src/services/vaultTimeout.service.ts @@ -12,6 +12,7 @@ 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 { @@ -42,10 +43,11 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { } // Keys aren't stored for a device that is locked or logged out. - async isLocked(): Promise { - // Handle never lock startup situation - if (await this.cryptoService.hasKeyStored(KeySuffixOptions.Auto) && !(await this.stateService.getEverBeenUnlocked())) { - await this.cryptoService.getKey(KeySuffixOptions.Auto); + async isLocked(userId?: string): Promise { + const neverLock = await this.cryptoService.hasKeyStored(KeySuffixOptions.Auto, userId) && + !(await this.stateService.getEverBeenUnlocked(userId ? {userId: userId, storageLocation: StorageLocation.Disk} : null)); + if (neverLock) { + return (await this.cryptoService.getKey(KeySuffixOptions.Auto, userId)) != null; } return !(await this.cryptoService.hasKeyInMemory()); @@ -86,24 +88,24 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { } } - async lock(allowSoftLock = false): Promise { - const authed = await this.stateService.getIsAuthenticated(); + async lock(allowSoftLock = false, userId?: string): Promise { + const authed = await this.stateService.getIsAuthenticated({ userId: userId }); if (!authed) { return; } - await this.stateService.setBiometricLocked(true); - await this.stateService.setEverBeenUnlocked(true); - await this.cryptoService.clearKey(false); - await this.cryptoService.clearOrgKeys(true); - await this.cryptoService.clearKeyPair(true); - await this.cryptoService.clearEncKey(true); + await this.stateService.setBiometricLocked(true, { userId: userId }); + await this.stateService.setEverBeenUnlocked(true, { userId: userId }); + await this.cryptoService.clearKey(false, userId); + await this.cryptoService.clearOrgKeys(true, userId); + await this.cryptoService.clearKeyPair(true, userId); + await this.cryptoService.clearEncKey(true, userId); - await this.folderService.clearCache(); - await this.cipherService.clearCache(); - await this.collectionService.clearCache(); + await this.folderService.clearCache(userId); + await this.cipherService.clearCache(userId); + await this.collectionService.clearCache(userId); this.searchService.clearIndex(); - this.messagingService.send('locked'); + this.messagingService.send('locked', { userId }); if (this.lockedCallback != null) { await this.lockedCallback(); }