1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-21001] Move tools usage of encrypt service (#14540)

* Add new encrypt service functions

* Undo changes

* Cleanup

* Fix build

* Fix comments

* Move tools usage of encrypt service
This commit is contained in:
Bernd Schoolmann
2025-04-30 15:36:48 +02:00
committed by GitHub
parent a92afe1efb
commit 67b0a19319
20 changed files with 61 additions and 54 deletions

View File

@@ -59,7 +59,7 @@ describe("CriticalAppsService", () => {
{ id: "id2", organizationId: "org1", uri: "https://example.org" },
] as PasswordHealthReportApplicationsResponse[];
encryptService.encrypt.mockResolvedValue(new EncString("encryptedUrlName"));
encryptService.encryptString.mockResolvedValue(new EncString("encryptedUrlName"));
criticalAppsApiService.saveCriticalApps.mockReturnValue(of(response));
// act
@@ -67,7 +67,7 @@ describe("CriticalAppsService", () => {
// expectations
expect(keyService.getOrgKey).toHaveBeenCalledWith("org1");
expect(encryptService.encrypt).toHaveBeenCalledTimes(2);
expect(encryptService.encryptString).toHaveBeenCalledTimes(2);
expect(criticalAppsApiService.saveCriticalApps).toHaveBeenCalledWith(request);
});
@@ -95,7 +95,7 @@ describe("CriticalAppsService", () => {
{ id: "id1", organizationId: "org1", uri: "test" },
] as PasswordHealthReportApplicationsResponse[];
encryptService.encrypt.mockResolvedValue(new EncString("encryptedUrlName"));
encryptService.encryptString.mockResolvedValue(new EncString("encryptedUrlName"));
criticalAppsApiService.saveCriticalApps.mockReturnValue(of(response));
// act
@@ -103,7 +103,7 @@ describe("CriticalAppsService", () => {
// expectations
expect(keyService.getOrgKey).toHaveBeenCalledWith("org1");
expect(encryptService.encrypt).toHaveBeenCalledTimes(1);
expect(encryptService.encryptString).toHaveBeenCalledTimes(1);
expect(criticalAppsApiService.saveCriticalApps).toHaveBeenCalledWith(request);
});
@@ -114,7 +114,7 @@ describe("CriticalAppsService", () => {
{ id: "id2", organizationId: "org1", uri: "https://example.org" },
] as PasswordHealthReportApplicationsResponse[];
encryptService.decryptToUtf8.mockResolvedValue("https://example.com");
encryptService.decryptString.mockResolvedValue("https://example.com");
criticalAppsApiService.getCriticalApps.mockReturnValue(of(response));
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
@@ -125,7 +125,7 @@ describe("CriticalAppsService", () => {
flush();
expect(keyService.getOrgKey).toHaveBeenCalledWith(orgId.toString());
expect(encryptService.decryptToUtf8).toHaveBeenCalledTimes(2);
expect(encryptService.decryptString).toHaveBeenCalledTimes(2);
expect(criticalAppsApiService.getCriticalApps).toHaveBeenCalledWith(orgId);
}));

View File

@@ -81,7 +81,7 @@ export class CriticalAppsService {
// add the new entries to the criticalAppsList
const updatedList = [...this.criticalAppsList.value];
for (const responseItem of dbResponse) {
const decryptedUrl = await this.encryptService.decryptToUtf8(
const decryptedUrl = await this.encryptService.decryptString(
new EncString(responseItem.uri),
key,
);
@@ -138,7 +138,7 @@ export class CriticalAppsService {
const results = response.map(async (r: PasswordHealthReportApplicationsResponse) => {
const encrypted = new EncString(r.uri);
const uri = await this.encryptService.decryptToUtf8(encrypted, key);
const uri = await this.encryptService.decryptString(encrypted, key);
return { id: r.id, organizationId: r.organizationId, uri: uri };
});
return forkJoin(results);
@@ -164,7 +164,7 @@ export class CriticalAppsService {
newEntries: string[],
): Promise<PasswordHealthReportApplicationsRequest[]> {
const criticalAppsPromises = newEntries.map(async (url) => {
const encryptedUrlName = await this.encryptService.encrypt(url, key);
const encryptedUrlName = await this.encryptService.encryptString(url, key);
return {
organizationId: orgId,
url: encryptedUrlName?.encryptedString?.toString() ?? "",

View File

@@ -22,8 +22,10 @@ describe("OrgKeyEncryptor", () => {
// on this property--that the facade treats its data like a opaque objects--to trace
// the data through several function calls. Should the encryptor interact with the
// objects themselves, these mocks will break.
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c as unknown as string));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptString.mockImplementation((c) => Promise.resolve(c as unknown as string));
dataPacker.pack.mockImplementation((v) => v as string);
dataPacker.unpack.mockImplementation(<T>(v: string) => v as T);
});
@@ -95,7 +97,7 @@ describe("OrgKeyEncryptor", () => {
// these are data flow expectations; the operations all all pass-through mocks
expect(dataPacker.pack).toHaveBeenCalledWith(value);
expect(encryptService.encrypt).toHaveBeenCalledWith(value, orgKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(value, orgKey);
expect(result).toBe(value);
});
});
@@ -117,7 +119,7 @@ describe("OrgKeyEncryptor", () => {
const result = await encryptor.decrypt(secret);
// these are data flow expectations; the operations all all pass-through mocks
expect(encryptService.decryptToUtf8).toHaveBeenCalledWith(secret, orgKey);
expect(encryptService.decryptString).toHaveBeenCalledWith(secret, orgKey);
expect(dataPacker.unpack).toHaveBeenCalledWith(secret);
expect(result).toBe(secret);
});

View File

@@ -37,7 +37,7 @@ export class OrganizationKeyEncryptor extends OrganizationEncryptor {
this.assertHasValue("secret", secret);
let packed = this.dataPacker.pack(secret);
const encrypted = await this.encryptService.encrypt(packed, this.key);
const encrypted = await this.encryptService.encryptString(packed, this.key);
packed = null;
return encrypted;
@@ -46,7 +46,7 @@ export class OrganizationKeyEncryptor extends OrganizationEncryptor {
async decrypt<Secret>(secret: EncString): Promise<Jsonify<Secret>> {
this.assertHasValue("secret", secret);
let decrypted = await this.encryptService.decryptToUtf8(secret, this.key);
let decrypted = await this.encryptService.decryptString(secret, this.key);
const unpacked = this.dataPacker.unpack<Secret>(decrypted);
decrypted = null;

View File

@@ -22,8 +22,10 @@ describe("UserKeyEncryptor", () => {
// on this property--that the facade treats its data like a opaque objects--to trace
// the data through several function calls. Should the encryptor interact with the
// objects themselves, these mocks will break.
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c as unknown as string));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptString.mockImplementation((c) => Promise.resolve(c as unknown as string));
dataPacker.pack.mockImplementation((v) => v as string);
dataPacker.unpack.mockImplementation(<T>(v: string) => v as T);
});
@@ -95,7 +97,7 @@ describe("UserKeyEncryptor", () => {
// these are data flow expectations; the operations all all pass-through mocks
expect(dataPacker.pack).toHaveBeenCalledWith(value);
expect(encryptService.encrypt).toHaveBeenCalledWith(value, userKey);
expect(encryptService.encryptString).toHaveBeenCalledWith(value, userKey);
expect(result).toBe(value);
});
});
@@ -117,7 +119,7 @@ describe("UserKeyEncryptor", () => {
const result = await encryptor.decrypt(secret);
// these are data flow expectations; the operations all all pass-through mocks
expect(encryptService.decryptToUtf8).toHaveBeenCalledWith(secret, userKey);
expect(encryptService.decryptString).toHaveBeenCalledWith(secret, userKey);
expect(dataPacker.unpack).toHaveBeenCalledWith(secret);
expect(result).toBe(secret);
});

View File

@@ -37,7 +37,7 @@ export class UserKeyEncryptor extends UserEncryptor {
this.assertHasValue("secret", secret);
let packed = this.dataPacker.pack(secret);
const encrypted = await this.encryptService.encrypt(packed, this.key);
const encrypted = await this.encryptService.encryptString(packed, this.key);
packed = null;
return encrypted;
@@ -46,7 +46,7 @@ export class UserKeyEncryptor extends UserEncryptor {
async decrypt<Secret>(secret: EncString): Promise<Jsonify<Secret>> {
this.assertHasValue("secret", secret);
let decrypted = await this.encryptService.decryptToUtf8(secret, this.key);
let decrypted = await this.encryptService.decryptString(secret, this.key);
const unpacked = this.dataPacker.unpack<Secret>(decrypted);
decrypted = null;

View File

@@ -112,7 +112,7 @@ describe("Send", () => {
const encryptService = mock<EncryptService>();
const keyService = mock<KeyService>();
encryptService.decryptToBytes
encryptService.decryptBytes
.calledWith(send.key, userKey)
.mockResolvedValue(makeStaticByteArray(32));
keyService.makeSendKey.mockResolvedValue("cryptoKey" as any);

View File

@@ -79,7 +79,8 @@ export class Send extends Domain {
try {
const sendKeyEncryptionKey = await keyService.getUserKey();
model.key = await encryptService.decryptToBytes(this.key, sendKeyEncryptionKey);
// model.key is a seed used to derive a key, not a SymmetricCryptoKey
model.key = await encryptService.decryptBytes(this.key, sendKeyEncryptionKey);
model.cryptoKey = await keyService.makeSendKey(model.key);
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@@ -477,7 +477,9 @@ describe("SendService", () => {
let encryptedKey: EncString;
beforeEach(() => {
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(32));
encryptService.unwrapSymmetricKey.mockResolvedValue(
new SymmetricCryptoKey(new Uint8Array(32)),
);
encryptedKey = new EncString("Re-encrypted Send Key");
encryptService.wrapSymmetricKey.mockResolvedValue(encryptedKey);
});

View File

@@ -86,12 +86,12 @@ export class SendService implements InternalSendServiceAbstraction {
userKey = await this.keyService.getUserKey();
}
// Key is not a SymmetricCryptoKey, but key material used to derive the cryptoKey
send.key = await this.encryptService.encrypt(model.key, userKey);
send.name = await this.encryptService.encrypt(model.name, model.cryptoKey);
send.notes = await this.encryptService.encrypt(model.notes, model.cryptoKey);
send.key = await this.encryptService.encryptBytes(model.key, userKey);
send.name = await this.encryptService.encryptString(model.name, model.cryptoKey);
send.notes = await this.encryptService.encryptString(model.notes, model.cryptoKey);
if (send.type === SendType.Text) {
send.text = new SendText();
send.text.text = await this.encryptService.encrypt(model.text.text, model.cryptoKey);
send.text.text = await this.encryptService.encryptString(model.text.text, model.cryptoKey);
send.text.hidden = model.text.hidden;
} else if (send.type === SendType.File) {
send.file = new SendFile();
@@ -292,9 +292,7 @@ export class SendService implements InternalSendServiceAbstraction {
) {
const requests = await Promise.all(
sends.map(async (send) => {
const sendKey = new SymmetricCryptoKey(
await this.encryptService.decryptToBytes(send.key, originalUserKey),
);
const sendKey = await this.encryptService.unwrapSymmetricKey(send.key, originalUserKey);
send.key = await this.encryptService.wrapSymmetricKey(sendKey, rotateUserKey);
return new SendWithIdRequest(send);
}),
@@ -333,8 +331,8 @@ export class SendService implements InternalSendServiceAbstraction {
if (key == null) {
key = await this.keyService.getUserKey();
}
const encFileName = await this.encryptService.encrypt(fileName, key);
const encFileData = await this.encryptService.encryptToBytes(new Uint8Array(data), key);
const encFileName = await this.encryptService.encryptString(fileName, key);
const encFileData = await this.encryptService.encryptFileData(new Uint8Array(data), key);
return [encFileName, encFileData];
}

View File

@@ -72,7 +72,7 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer {
keyForDecryption = await this.keyService.getUserKeyWithLegacySupport();
}
const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT);
const encKeyValidationDecrypt = await this.encryptService.decryptToUtf8(
const encKeyValidationDecrypt = await this.encryptService.decryptString(
encKeyValidation,
keyForDecryption,
);

View File

@@ -92,7 +92,7 @@ describe("BitwardenPasswordProtectedImporter", () => {
});
it("succeeds with default jdoc", async () => {
encryptService.decryptToUtf8.mockReturnValue(Promise.resolve(emptyUnencryptedExport));
encryptService.decryptString.mockReturnValue(Promise.resolve(emptyUnencryptedExport));
expect((await importer.parse(JSON.stringify(jDoc))).success).toEqual(true);
});

View File

@@ -69,7 +69,7 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
}
const encData = new EncString(parsedData.data);
const clearTextData = await this.encryptService.decryptToUtf8(encData, this.key);
const clearTextData = await this.encryptService.decryptString(encData, this.key);
return await super.parse(clearTextData);
}
@@ -90,7 +90,7 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
const encKeyValidation = new EncString(jdoc.encKeyValidation_DO_NOT_EDIT);
const encKeyValidationDecrypt = await this.encryptService.decryptToUtf8(
const encKeyValidationDecrypt = await this.encryptService.decryptString(
encKeyValidation,
this.key,
);

View File

@@ -28,8 +28,8 @@ export class BaseVaultExportService {
const salt = Utils.fromBufferToB64(await this.cryptoFunctionService.randomBytes(16));
const key = await this.pinService.makePinKey(password, salt, kdfConfig);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), key);
const encText = await this.encryptService.encrypt(clearText, key);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), key);
const encText = await this.encryptService.encryptString(clearText, key);
const jsonDoc: BitwardenPasswordProtectedFileFormat = {
encrypted: true,

View File

@@ -209,7 +209,7 @@ describe("VaultExportService", () => {
folderService.folderViews$.mockReturnValue(of(UserFolderViews));
folderService.folders$.mockReturnValue(of(UserFolders));
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encryptString.mockResolvedValue(new EncString("encrypted"));
apiService.getAttachmentData.mockResolvedValue(attachmentResponse);
exportService = new IndividualVaultExportService(
@@ -313,7 +313,7 @@ describe("VaultExportService", () => {
cipherService.getAllDecrypted.mockResolvedValue([cipherView]);
folderService.getAllDecryptedFromState.mockResolvedValue([]);
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(255));
encryptService.decryptFileData.mockResolvedValue(new Uint8Array(255));
global.fetch = jest.fn(() =>
Promise.resolve({
@@ -338,7 +338,7 @@ describe("VaultExportService", () => {
cipherService.getAllDecrypted.mockResolvedValue([cipherView]);
folderService.getAllDecryptedFromState.mockResolvedValue([]);
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(255));
encryptService.decryptFileData.mockResolvedValue(new Uint8Array(255));
global.fetch = jest.fn(() =>
Promise.resolve({
@@ -362,7 +362,7 @@ describe("VaultExportService", () => {
cipherView.attachments = [attachmentView];
cipherService.getAllDecrypted.mockResolvedValue([cipherView]);
folderService.getAllDecryptedFromState.mockResolvedValue([]);
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(255));
encryptService.decryptFileData.mockResolvedValue(new Uint8Array(255));
global.fetch = jest.fn(() =>
Promise.resolve({
status: 200,
@@ -427,7 +427,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
encryptService.encrypt.mockResolvedValue(mac);
encryptService.encryptString.mockResolvedValue(mac);
exportedVault = await exportService.getPasswordProtectedExport(password);
exportString = exportedVault.data;
exportObject = JSON.parse(exportString);
@@ -436,7 +436,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
encryptService.encrypt.mockResolvedValue(data);
encryptService.encryptString.mockResolvedValue(data);
exportedVault = await exportService.getPasswordProtectedExport(password);
exportString = exportedVault.data;
exportObject = JSON.parse(exportString);

View File

@@ -157,7 +157,7 @@ export class IndividualVaultExportService
attachment.key != null
? attachment.key
: await this.keyService.getOrgKey(cipher.organizationId);
return await this.encryptService.decryptToBytes(encBuf, key);
return await this.encryptService.decryptFileData(encBuf, key);
} catch {
throw new Error("Error decrypting attachment");
}
@@ -220,7 +220,7 @@ export class IndividualVaultExportService
await Promise.all(promises);
const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), userKey);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), userKey);
const jsonDoc: BitwardenEncryptedIndividualJsonExport = {
encrypted: true,

View File

@@ -286,7 +286,7 @@ export class OrganizationVaultExportService
ciphers: Cipher[],
): Promise<string> {
const orgKey = await this.keyService.getOrgKey(organizationId);
const encKeyValidation = await this.encryptService.encrypt(Utils.newGuid(), orgKey);
const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), orgKey);
const jsonDoc: BitwardenEncryptedOrgJsonExport = {
encrypted: true,

View File

@@ -175,7 +175,7 @@ describe("VaultExportService", () => {
folderService.folderViews$.mockReturnValue(of(UserFolderViews));
folderService.folders$.mockReturnValue(of(UserFolders));
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
encryptService.encrypt.mockResolvedValue(new EncString("encrypted"));
encryptService.encryptString.mockResolvedValue(new EncString("encrypted"));
keyService.userKey$.mockReturnValue(new BehaviorSubject("mockOriginalUserKey" as any));
const userId = "" as UserId;
const accountInfo: AccountInfo = {
@@ -282,7 +282,7 @@ describe("VaultExportService", () => {
});
it("has a mac property", async () => {
encryptService.encrypt.mockResolvedValue(mac);
encryptService.encryptString.mockResolvedValue(mac);
exportedVault = await exportService.getPasswordProtectedExport(password);
@@ -293,7 +293,7 @@ describe("VaultExportService", () => {
});
it("has data property", async () => {
encryptService.encrypt.mockResolvedValue(data);
encryptService.encryptString.mockResolvedValue(data);
exportedVault = await exportService.getPasswordProtectedExport(password);

View File

@@ -19,7 +19,7 @@ export class LegacyPasswordHistoryDecryptor {
const promises = (history ?? []).map(async (item) => {
const encrypted = new EncString(item.password);
const decrypted = await this.encryptService.decryptToUtf8(encrypted, key);
const decrypted = await this.encryptService.decryptString(encrypted, key);
return new GeneratedPasswordHistory(decrypted, item.date);
});

View File

@@ -22,8 +22,10 @@ describe("LocalGeneratorHistoryService", () => {
const userKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as UserKey;
beforeEach(() => {
encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString));
encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c.encryptedString));
encryptService.encryptString.mockImplementation((p) =>
Promise.resolve(p as unknown as EncString),
);
encryptService.decryptString.mockImplementation((c) => Promise.resolve(c.encryptedString));
keyService.getUserKey.mockImplementation(() => Promise.resolve(userKey));
keyService.userKey$.mockImplementation(() => of(true as unknown as UserKey));
});