mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[PS-11868] Require key for enc string decryption (#10981)
* Specify enc string decryption key and service. * Fix issue with identifying `this` type within extended classes * Folder decryption example * Test enc string changes * Fix test name * test decrypt with key
This commit is contained in:
@@ -1,8 +1,18 @@
|
||||
import { ConditionalExcept, ConditionalKeys, Constructor } from "type-fest";
|
||||
|
||||
import { View } from "../../../models/view/view";
|
||||
import { EncryptService } from "../../abstractions/encrypt.service";
|
||||
|
||||
import { EncString } from "./enc-string";
|
||||
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type EncStringKeys<T> = ConditionalKeys<ConditionalExcept<T, Function>, EncString>;
|
||||
export type DecryptedObject<
|
||||
TEncryptedObject,
|
||||
TDecryptedKeys extends EncStringKeys<TEncryptedObject>,
|
||||
> = Record<TDecryptedKeys, string> & Omit<TEncryptedObject, TDecryptedKeys>;
|
||||
|
||||
// https://contributing.bitwarden.com/architecture/clients/data-model#domain
|
||||
export default class Domain {
|
||||
protected buildDomainModel<D extends Domain>(
|
||||
@@ -80,4 +90,60 @@ export default class Domain {
|
||||
await Promise.all(promises);
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the requested properties of the domain object with the provided key and encrypt service.
|
||||
*
|
||||
* If a property is null, the result will be null.
|
||||
* @see {@link EncString.decryptWithKey} for more details on decryption behavior.
|
||||
*
|
||||
* @param encryptedProperties The properties to decrypt. Type restricted to EncString properties of the domain object.
|
||||
* @param key The key to use for decryption.
|
||||
* @param encryptService The encryption service to use for decryption.
|
||||
* @param _ The constructor of the domain object. Used for type inference if the domain object is not automatically inferred.
|
||||
* @returns An object with the requested properties decrypted and the rest of the domain object untouched.
|
||||
*/
|
||||
protected async decryptObjWithKey<
|
||||
TThis extends Domain,
|
||||
const TEncryptedKeys extends EncStringKeys<TThis>,
|
||||
>(
|
||||
this: TThis,
|
||||
encryptedProperties: TEncryptedKeys[],
|
||||
key: SymmetricCryptoKey,
|
||||
encryptService: EncryptService,
|
||||
_: Constructor<TThis> = this.constructor as Constructor<TThis>,
|
||||
): Promise<DecryptedObject<TThis, TEncryptedKeys>> {
|
||||
const promises = [];
|
||||
|
||||
for (const prop of encryptedProperties) {
|
||||
const value = (this as any)[prop] as EncString;
|
||||
promises.push(this.decryptProperty(prop, value, key, encryptService));
|
||||
}
|
||||
|
||||
const decryptedObjects = await Promise.all(promises);
|
||||
const decryptedObject = decryptedObjects.reduce(
|
||||
(acc, obj) => {
|
||||
return { ...acc, ...obj };
|
||||
},
|
||||
{ ...this },
|
||||
);
|
||||
return decryptedObject as DecryptedObject<TThis, TEncryptedKeys>;
|
||||
}
|
||||
|
||||
private async decryptProperty<const TEncryptedKeys extends EncStringKeys<this>>(
|
||||
propertyKey: TEncryptedKeys,
|
||||
value: EncString,
|
||||
key: SymmetricCryptoKey,
|
||||
encryptService: EncryptService,
|
||||
) {
|
||||
let decrypted: string = null;
|
||||
if (value) {
|
||||
decrypted = await value.decryptWithKey(key, encryptService);
|
||||
} else {
|
||||
decrypted = null;
|
||||
}
|
||||
return {
|
||||
[propertyKey]: decrypted,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user