mirror of
https://github.com/bitwarden/browser
synced 2026-01-01 16:13:27 +00:00
Remove decrypt with key from EncString, domain-base (#15702)
This commit is contained in:
@@ -1,131 +0,0 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { makeEncString, makeSymmetricCryptoKey } from "../../../../spec";
|
||||
import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||
|
||||
import Domain from "./domain-base";
|
||||
|
||||
class TestDomain extends Domain {
|
||||
plainText: string;
|
||||
encToString: EncString;
|
||||
encString2: EncString;
|
||||
}
|
||||
|
||||
describe("DomainBase", () => {
|
||||
let encryptService: MockProxy<EncryptService>;
|
||||
const key = makeSymmetricCryptoKey(64);
|
||||
|
||||
beforeEach(() => {
|
||||
encryptService = mock<EncryptService>();
|
||||
});
|
||||
|
||||
function setUpCryptography() {
|
||||
encryptService.encryptString.mockImplementation((value) =>
|
||||
Promise.resolve(makeEncString(value)),
|
||||
);
|
||||
|
||||
encryptService.decryptString.mockImplementation((value) => {
|
||||
return Promise.resolve(value.data);
|
||||
});
|
||||
}
|
||||
|
||||
describe("decryptWithKey", () => {
|
||||
it("domain property types are decryptable", async () => {
|
||||
const domain = new TestDomain();
|
||||
|
||||
await domain["decryptObjWithKey"](
|
||||
// @ts-expect-error -- clear is not of type EncString
|
||||
["plainText"],
|
||||
makeSymmetricCryptoKey(64),
|
||||
mock<EncryptService>(),
|
||||
);
|
||||
|
||||
await domain["decryptObjWithKey"](
|
||||
// @ts-expect-error -- Clear is not of type EncString
|
||||
["encToString", "encString2", "plainText"],
|
||||
makeSymmetricCryptoKey(64),
|
||||
mock<EncryptService>(),
|
||||
);
|
||||
|
||||
const decrypted = await domain["decryptObjWithKey"](
|
||||
["encToString"],
|
||||
makeSymmetricCryptoKey(64),
|
||||
mock<EncryptService>(),
|
||||
);
|
||||
|
||||
// @ts-expect-error -- encString2 was not decrypted
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
decrypted as { encToString: string; encString2: string; plainText: string };
|
||||
|
||||
// encString2 was not decrypted, so it's still an EncString
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
decrypted as { encToString: string; encString2: EncString; plainText: string };
|
||||
});
|
||||
|
||||
it("decrypts the encrypted properties", async () => {
|
||||
setUpCryptography();
|
||||
|
||||
const domain = new TestDomain();
|
||||
|
||||
domain.encToString = await encryptService.encryptString("string", key);
|
||||
|
||||
const decrypted = await domain["decryptObjWithKey"](["encToString"], key, encryptService);
|
||||
|
||||
expect(decrypted).toEqual({
|
||||
encToString: "string",
|
||||
});
|
||||
});
|
||||
|
||||
it("decrypts multiple encrypted properties", async () => {
|
||||
setUpCryptography();
|
||||
|
||||
const domain = new TestDomain();
|
||||
|
||||
domain.encToString = await encryptService.encryptString("string", key);
|
||||
domain.encString2 = await encryptService.encryptString("string2", key);
|
||||
|
||||
const decrypted = await domain["decryptObjWithKey"](
|
||||
["encToString", "encString2"],
|
||||
key,
|
||||
encryptService,
|
||||
);
|
||||
|
||||
expect(decrypted).toEqual({
|
||||
encToString: "string",
|
||||
encString2: "string2",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not decrypt properties that are not encrypted", async () => {
|
||||
const domain = new TestDomain();
|
||||
domain.plainText = "clear";
|
||||
|
||||
const decrypted = await domain["decryptObjWithKey"]([], key, encryptService);
|
||||
|
||||
expect(decrypted).toEqual({
|
||||
plainText: "clear",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not decrypt properties that were not requested to be decrypted", async () => {
|
||||
setUpCryptography();
|
||||
|
||||
const domain = new TestDomain();
|
||||
|
||||
domain.plainText = "clear";
|
||||
domain.encToString = makeEncString("string");
|
||||
domain.encString2 = makeEncString("string2");
|
||||
|
||||
const decrypted = await domain["decryptObjWithKey"]([], key, encryptService);
|
||||
|
||||
expect(decrypted).toEqual({
|
||||
plainText: "clear",
|
||||
encToString: makeEncString("string"),
|
||||
encString2: makeEncString("string2"),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ConditionalExcept, ConditionalKeys, Constructor } from "type-fest";
|
||||
import { ConditionalExcept, ConditionalKeys } from "type-fest";
|
||||
|
||||
import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||
import { View } from "../../../models/view/view";
|
||||
|
||||
@@ -89,66 +88,4 @@ export default class Domain {
|
||||
|
||||
return viewModel as V;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>,
|
||||
objectContext: string = "No Domain Context",
|
||||
): Promise<DecryptedObject<TThis, TEncryptedKeys>> {
|
||||
const decryptedObjects = [];
|
||||
|
||||
for (const prop of encryptedProperties) {
|
||||
const value = this[prop] as EncString;
|
||||
const decrypted = await this.decryptProperty(
|
||||
prop,
|
||||
value,
|
||||
key,
|
||||
encryptService,
|
||||
`Property: ${prop.toString()}; ObjectContext: ${objectContext}`,
|
||||
);
|
||||
decryptedObjects.push(decrypted);
|
||||
}
|
||||
|
||||
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,
|
||||
decryptTrace: string,
|
||||
) {
|
||||
let decrypted: string | null = null;
|
||||
if (value) {
|
||||
decrypted = await value.decryptWithKey(key, encryptService, decryptTrace);
|
||||
}
|
||||
return {
|
||||
[propertyKey]: decrypted,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user