mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
[PM-10607] Require userId for getKeyForCipherKeyDecryption (#10509)
* updated cipher service to stop using the deprecated getUserKeyWithLegacySupport and use the version that requires a user id * Added account service mock * fixed cipher test * Fixed test * removed async from encryptCipher * updated encryptSharedCipher to pass userId to the encrypt function * Pass userId to getUserKeyWithLegacySupport on encryptSharedCipher * pass in userid when setting masterKeyEncryptedUserKey * Added activer usedId to new web refresh function
This commit is contained in:
@@ -165,6 +165,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
async encrypt(
|
||||
model: CipherView,
|
||||
userId: UserId,
|
||||
keyForEncryption?: SymmetricCryptoKey,
|
||||
keyForCipherKeyDecryption?: SymmetricCryptoKey,
|
||||
originalCipher: Cipher = null,
|
||||
@@ -174,7 +175,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
originalCipher = await this.get(model.id);
|
||||
}
|
||||
if (originalCipher != null) {
|
||||
await this.updateModelfromExistingCipher(model, originalCipher);
|
||||
await this.updateModelfromExistingCipher(model, originalCipher, userId);
|
||||
}
|
||||
this.adjustPasswordHistoryLength(model);
|
||||
}
|
||||
@@ -192,7 +193,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
if (await this.getCipherKeyEncryptionEnabled()) {
|
||||
cipher.key = originalCipher?.key ?? null;
|
||||
const userOrOrgKey = await this.getKeyForCipherKeyDecryption(cipher);
|
||||
const userOrOrgKey = await this.getKeyForCipherKeyDecryption(cipher, userId);
|
||||
// The keyForEncryption is only used for encrypting the cipher key, not the cipher itself, since cipher key encryption is enabled.
|
||||
// If the caller has provided a key for cipher key encryption, use it. Otherwise, use the user or org key.
|
||||
keyForEncryption ||= userOrOrgKey;
|
||||
@@ -718,6 +719,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
cipher: CipherView,
|
||||
organizationId: string,
|
||||
collectionIds: string[],
|
||||
userId: UserId,
|
||||
): Promise<any> {
|
||||
const attachmentPromises: Promise<any>[] = [];
|
||||
if (cipher.attachments != null) {
|
||||
@@ -733,7 +735,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
cipher.organizationId = organizationId;
|
||||
cipher.collectionIds = collectionIds;
|
||||
const encCipher = await this.encryptSharedCipher(cipher);
|
||||
const encCipher = await this.encryptSharedCipher(cipher, userId);
|
||||
const request = new CipherShareRequest(encCipher);
|
||||
const response = await this.apiService.putShareCipher(cipher.id, request);
|
||||
const data = new CipherData(response, collectionIds);
|
||||
@@ -744,6 +746,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
ciphers: CipherView[],
|
||||
organizationId: string,
|
||||
collectionIds: string[],
|
||||
userId: UserId,
|
||||
): Promise<any> {
|
||||
const promises: Promise<any>[] = [];
|
||||
const encCiphers: Cipher[] = [];
|
||||
@@ -751,7 +754,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
cipher.organizationId = organizationId;
|
||||
cipher.collectionIds = collectionIds;
|
||||
promises.push(
|
||||
this.encryptSharedCipher(cipher).then((c) => {
|
||||
this.encryptSharedCipher(cipher, userId).then((c) => {
|
||||
encCiphers.push(c);
|
||||
}),
|
||||
);
|
||||
@@ -770,7 +773,12 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
await this.upsert(encCiphers.map((c) => c.toCipherData()));
|
||||
}
|
||||
|
||||
saveAttachmentWithServer(cipher: Cipher, unencryptedFile: any, admin = false): Promise<Cipher> {
|
||||
saveAttachmentWithServer(
|
||||
cipher: Cipher,
|
||||
unencryptedFile: any,
|
||||
userId: UserId,
|
||||
admin = false,
|
||||
): Promise<Cipher> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(unencryptedFile);
|
||||
@@ -780,6 +788,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
cipher,
|
||||
unencryptedFile.name,
|
||||
evt.target.result,
|
||||
userId,
|
||||
admin,
|
||||
);
|
||||
resolve(cData);
|
||||
@@ -797,9 +806,10 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
cipher: Cipher,
|
||||
filename: string,
|
||||
data: Uint8Array,
|
||||
userId: UserId,
|
||||
admin = false,
|
||||
): Promise<Cipher> {
|
||||
const encKey = await this.getKeyForCipherKeyDecryption(cipher);
|
||||
const encKey = await this.getKeyForCipherKeyDecryption(cipher, userId);
|
||||
const cipherKeyEncryptionEnabled = await this.getCipherKeyEncryptionEnabled();
|
||||
|
||||
const cipherEncKey =
|
||||
@@ -813,8 +823,8 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
//then we rollback to using the user key as the main key of encryption of the item
|
||||
//in order to keep item and it's attachments with the same encryption level
|
||||
if (cipher.key != null && !cipherKeyEncryptionEnabled) {
|
||||
const model = await cipher.decrypt(await this.getKeyForCipherKeyDecryption(cipher));
|
||||
cipher = await this.encrypt(model);
|
||||
const model = await cipher.decrypt(await this.getKeyForCipherKeyDecryption(cipher, userId));
|
||||
cipher = await this.encrypt(model, userId);
|
||||
await this.updateWithServer(cipher);
|
||||
}
|
||||
|
||||
@@ -1209,10 +1219,10 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
await this.restore(restores);
|
||||
}
|
||||
|
||||
async getKeyForCipherKeyDecryption(cipher: Cipher): Promise<UserKey | OrgKey> {
|
||||
async getKeyForCipherKeyDecryption(cipher: Cipher, userId: UserId): Promise<UserKey | OrgKey> {
|
||||
return (
|
||||
(await this.cryptoService.getOrgKey(cipher.organizationId)) ||
|
||||
((await this.cryptoService.getUserKeyWithLegacySupport()) as UserKey)
|
||||
((await this.cryptoService.getUserKeyWithLegacySupport(userId)) as UserKey)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1247,7 +1257,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
}
|
||||
encryptedCiphers = await Promise.all(
|
||||
userCiphers.map(async (cipher) => {
|
||||
const encryptedCipher = await this.encrypt(cipher, newUserKey, originalUserKey);
|
||||
const encryptedCipher = await this.encrypt(cipher, userId, newUserKey, originalUserKey);
|
||||
return new CipherWithIdRequest(encryptedCipher);
|
||||
}),
|
||||
);
|
||||
@@ -1259,17 +1269,18 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
|
||||
// In the case of a cipher that is being shared with an organization, we want to decrypt the
|
||||
// cipher key with the user's key and then re-encrypt it with the organization's key.
|
||||
private async encryptSharedCipher(model: CipherView): Promise<Cipher> {
|
||||
const keyForCipherKeyDecryption = await this.cryptoService.getUserKeyWithLegacySupport();
|
||||
return await this.encrypt(model, null, keyForCipherKeyDecryption);
|
||||
private async encryptSharedCipher(model: CipherView, userId: UserId): Promise<Cipher> {
|
||||
const keyForCipherKeyDecryption = await this.cryptoService.getUserKeyWithLegacySupport(userId);
|
||||
return await this.encrypt(model, userId, null, keyForCipherKeyDecryption);
|
||||
}
|
||||
|
||||
private async updateModelfromExistingCipher(
|
||||
model: CipherView,
|
||||
originalCipher: Cipher,
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
const existingCipher = await originalCipher.decrypt(
|
||||
await this.getKeyForCipherKeyDecryption(originalCipher),
|
||||
await this.getKeyForCipherKeyDecryption(originalCipher, userId),
|
||||
);
|
||||
model.passwordHistory = existingCipher.passwordHistory || [];
|
||||
if (model.type === CipherType.Login && existingCipher.type === CipherType.Login) {
|
||||
|
||||
Reference in New Issue
Block a user