1
0
mirror of https://github.com/bitwarden/jslib synced 2025-12-26 21:23:53 +00:00

[bug] Allow the lock message handler to manipulate a specific acount

This commit is contained in:
addison
2021-11-03 13:21:42 -04:00
parent b7b0c751e7
commit fde15347a5
10 changed files with 75 additions and 66 deletions

View File

@@ -11,7 +11,7 @@ import { CipherView } from '../models/view/cipherView';
import { FieldView } from '../models/view/fieldView';
export abstract class CipherService {
clearCache: () => Promise<void>;
clearCache: (userId?: string) => Promise<void>;
encrypt: (model: CipherView, key?: SymmetricCryptoKey, originalCipher?: Cipher) => Promise<Cipher>;
encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise<Field[]>;
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;

View File

@@ -6,7 +6,7 @@ import { TreeNode } from '../models/domain/treeNode';
import { CollectionView } from '../models/view/collectionView';
export abstract class CollectionService {
clearCache: () => Promise<void>;
clearCache: (userId?: string) => Promise<void>;
encrypt: (model: CollectionView) => Promise<Collection>;
decryptMany: (collections: Collection[]) => Promise<CollectionView[]>;
get: (id: string) => Promise<Collection>;

View File

@@ -17,7 +17,7 @@ export abstract class CryptoService {
setEncPrivateKey: (encPrivateKey: string) => Promise<void>;
setOrgKeys: (orgs: ProfileOrganizationResponse[], providerOrgs: ProfileProviderOrganizationResponse[]) => Promise<void>;
setProviderKeys: (orgs: ProfileProviderResponse[]) => Promise<void>;
getKey: (keySuffix?: KeySuffixOptions) => Promise<SymmetricCryptoKey>;
getKey: (keySuffix?: KeySuffixOptions, userId?: string) => Promise<SymmetricCryptoKey>;
getKeyFromStorage: (keySuffix: KeySuffixOptions) => Promise<SymmetricCryptoKey>;
getKeyHash: () => Promise<string>;
compareAndUpdateKeyHash: (masterPassword: string, key: SymmetricCryptoKey) => Promise<boolean>;
@@ -30,13 +30,13 @@ export abstract class CryptoService {
getProviderKey: (providerId: string) => Promise<SymmetricCryptoKey>;
hasKey: () => Promise<boolean>;
hasKeyInMemory: () => Promise<boolean>;
hasKeyStored: (keySuffix?: KeySuffixOptions) => Promise<boolean>;
hasKeyStored: (keySuffix?: KeySuffixOptions, userId?: string) => Promise<boolean>;
hasEncKey: () => Promise<boolean>;
clearKey: (clearSecretStorage?: boolean) => Promise<any>;
clearKey: (clearSecretStorage?: boolean, userId?: string) => Promise<any>;
clearKeyHash: () => Promise<any>;
clearEncKey: (memoryOnly?: boolean) => Promise<any>;
clearKeyPair: (memoryOnly?: boolean) => Promise<any>;
clearOrgKeys: (memoryOnly?: boolean) => Promise<any>;
clearEncKey: (memoryOnly?: boolean, userId?: string) => Promise<any>;
clearKeyPair: (memoryOnly?: boolean, userId?: string) => Promise<any>;
clearOrgKeys: (memoryOnly?: boolean, userId?: string) => Promise<any>;
clearProviderKeys: (memoryOnly?: boolean) => Promise<any>;
clearPinProtectedKey: () => Promise<any>;
clearKeys: () => Promise<any>;

View File

@@ -7,7 +7,7 @@ import { TreeNode } from '../models/domain/treeNode';
import { FolderView } from '../models/view/folderView';
export abstract class FolderService {
clearCache: () => Promise<void>;
clearCache: (userId?: string) => Promise<void>;
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
get: (id: string) => Promise<Folder>;
getAll: () => Promise<Folder[]>;

View File

@@ -1,7 +1,7 @@
export abstract class VaultTimeoutService {
isLocked: () => Promise<boolean>;
isLocked: (userId?: string) => Promise<boolean>;
checkVaultTimeout: () => Promise<void>;
lock: (allowSoftLock?: boolean) => Promise<void>;
lock: (allowSoftLock?: boolean, userId?: string) => Promise<void>;
logOut: () => Promise<void>;
setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise<void>;
getVaultTimeout: () => Promise<number>;

View File

@@ -81,8 +81,8 @@ export class CipherService implements CipherServiceAbstraction {
}
}
async clearCache(): Promise<void> {
await this.clearDecryptedCiphersState();
async clearCache(userId?: string): Promise<void> {
await this.clearDecryptedCiphersState(userId);
}
async encrypt(model: CipherView, key?: SymmetricCryptoKey, originalCipher: Cipher = null): Promise<Cipher> {
@@ -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();
}

View File

@@ -20,8 +20,8 @@ export class CollectionService implements CollectionServiceAbstraction {
private stateService: StateService) {
}
async clearCache(): Promise<void> {
await this.stateService.setDecryptedCollections(null);
async clearCache(userId?: string): Promise<void> {
await this.stateService.setDecryptedCollections(null, { userId });
}
async encrypt(model: CollectionView): Promise<Collection> {

View File

@@ -30,11 +30,14 @@ export class CryptoService implements CryptoServiceAbstraction {
protected logService: LogService, protected stateService: StateService) {
}
async setKey(key: SymmetricCryptoKey): Promise<any> {
await this.stateService.setCryptoMasterKey(key);
async setKey(key: SymmetricCryptoKey, userId?: string): Promise<any> {
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<SymmetricCryptoKey> {
const inMemoryKey = await this.stateService.getCryptoMasterKey();
async getKey(keySuffix?: KeySuffixOptions, userId?: string): Promise<SymmetricCryptoKey> {
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<SymmetricCryptoKey> {
const key = await this.retrieveKeyFromStorage(keySuffix);
async getKeyFromStorage(keySuffix: KeySuffixOptions, userId?: string): Promise<SymmetricCryptoKey> {
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<boolean> {
return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix }) != null;
async hasKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise<boolean> {
return await this.stateService.getCryptoMasterKeyB64({ keySuffix: keySuffix, userId }) != null;
}
async hasEncKey(): Promise<boolean> {
return await this.stateService.getDecryptedCryptoSymmetricKey() != null;
}
async clearKey(clearSecretStorage: boolean = true): Promise<any> {
await this.stateService.setCryptoMasterKey(null);
await this.stateService.setLegacyEtmKey(null);
async clearKey(clearSecretStorage: boolean = true, userId?: string): Promise<any> {
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<void> {
await this.stateService.setDecryptedCryptoSymmetricKey(null);
async clearEncKey(memoryOnly?: boolean, userId?: string): Promise<void> {
await this.stateService.setDecryptedCryptoSymmetricKey(null, { userId });
if (!memoryOnly) {
await this.stateService.setEncryptedCryptoSymmetricKey(null);
await this.stateService.setEncryptedCryptoSymmetricKey(null, { userId });
}
}
async clearKeyPair(memoryOnly?: boolean): Promise<any> {
async clearKeyPair(memoryOnly?: boolean, userId?: string): Promise<any> {
const keysToClear: Promise<void>[] = [
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<void> {
await this.stateService.setDecryptedOrganizationKeys(null);
async clearOrgKeys(memoryOnly?: boolean, userId?: string): Promise<void> {
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<EncryptedObject> {
@@ -876,8 +883,8 @@ export class CryptoService implements CryptoServiceAbstraction {
null;
}
private async clearSecretKeyStore(): Promise<void> {
await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Auto });
await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Biometric });
private async clearSecretKeyStore(userId?: string): Promise<void> {
await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Auto, userId });
await this.stateService.setCryptoMasterKeyB64(null, { keySuffix: KeySuffixOptions.Biometric, userId });
}
}

View File

@@ -29,8 +29,8 @@ export class FolderService implements FolderServiceAbstraction {
private i18nService: I18nService, private cipherService: CipherService,
private stateService: StateService) { }
async clearCache(): Promise<void> {
await this.stateService.setDecryptedFolders(null);
async clearCache(userId?: string): Promise<void> {
await this.stateService.setDecryptedFolders(null, { userId });
}
async encrypt(model: FolderView, key?: SymmetricCryptoKey): Promise<Folder> {

View File

@@ -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<boolean> {
// 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<boolean> {
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<void> {
const authed = await this.stateService.getIsAuthenticated();
async lock(allowSoftLock = false, userId?: string): Promise<void> {
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();
}