From 0072fda7653c1399cdd507c1dcd306d80e1a6388 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 29 Oct 2025 18:34:47 +0100 Subject: [PATCH] Update spec to not use EncString decrypt --- libs/common/spec/utils.ts | 15 ++++++- .../src/tools/send/models/domain/send.spec.ts | 7 +-- .../vault/models/domain/attachment.spec.ts | 16 +++---- .../src/vault/models/domain/card.spec.ts | 12 +++++- .../src/vault/models/domain/cipher.spec.ts | 43 ++++++------------- .../models/domain/fido2-credential.spec.ts | 7 ++- .../src/vault/models/domain/field.spec.ts | 3 +- .../src/vault/models/domain/folder.spec.ts | 9 +++- .../src/vault/models/domain/identity.spec.ts | 4 +- .../src/vault/models/domain/login-uri.spec.ts | 4 +- .../src/vault/models/domain/login-uri.ts | 6 +-- .../src/vault/models/domain/login.spec.ts | 6 ++- .../src/vault/models/domain/password.spec.ts | 3 +- .../vault/models/domain/secure-note.spec.ts | 3 ++ .../src/vault/models/domain/ssh-key.spec.ts | 4 +- .../src/vault/services/cipher.service.spec.ts | 7 ++- 16 files changed, 85 insertions(+), 64 deletions(-) diff --git a/libs/common/spec/utils.ts b/libs/common/spec/utils.ts index db9a7e0842c..76b33a8b88f 100644 --- a/libs/common/spec/utils.ts +++ b/libs/common/spec/utils.ts @@ -2,7 +2,10 @@ // @ts-strict-ignore import { mock, MockProxy } from "jest-mock-extended"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { ContainerService } from "@bitwarden/common/platform/services/container.service"; +import { KeyService } from "@bitwarden/key-management"; import { EncryptionType } from "../src/platform/enums"; import { Utils } from "../src/platform/misc/utils"; @@ -29,7 +32,7 @@ export function BuildTestObject( export function mockEnc(s: string): MockProxy { const mocked = mock(); - mocked.decrypt.mockResolvedValue(s); + mocked.decryptedValue = s; return mocked; } @@ -77,4 +80,14 @@ export const mockFromSdk = (stub: any) => { return `${stub}_fromSdk`; }; +export const mockContainerService = () => { + const keyService = mock(); + const encryptService = mock(); + encryptService.decryptString.mockImplementation(async (encStr, _key) => { + return encStr.decryptedValue; + }); + (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); + return (window as any).bitwardenContainerService; +}; + export { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils"; diff --git a/libs/common/src/tools/send/models/domain/send.spec.ts b/libs/common/src/tools/send/models/domain/send.spec.ts index d465aa97924..4c79d9ae40c 100644 --- a/libs/common/src/tools/send/models/domain/send.spec.ts +++ b/libs/common/src/tools/send/models/domain/send.spec.ts @@ -130,12 +130,7 @@ describe("Send", () => { const view = await send.decrypt(userId); expect(text.decrypt).toHaveBeenNthCalledWith(1, "cryptoKey"); - expect(send.name.decrypt).toHaveBeenNthCalledWith( - 1, - null, - "cryptoKey", - "Property: name; ObjectContext: No Domain Context", - ); + expect(encryptService.decryptString).toHaveBeenNthCalledWith(1, send.name, "cryptoKey"); expect(view).toMatchObject({ id: "id", diff --git a/libs/common/src/vault/models/domain/attachment.spec.ts b/libs/common/src/vault/models/domain/attachment.spec.ts index 5fc4e87edcc..eeda0f27880 100644 --- a/libs/common/src/vault/models/domain/attachment.spec.ts +++ b/libs/common/src/vault/models/domain/attachment.spec.ts @@ -4,12 +4,10 @@ import { mock, MockProxy } from "jest-mock-extended"; // eslint-disable-next-line no-restricted-imports import { KeyService } from "@bitwarden/key-management"; -import { makeStaticByteArray, mockEnc, mockFromJson } from "../../../../spec"; +import { makeStaticByteArray, mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; -import { ContainerService } from "../../../platform/services/container.service"; -import { UserKey } from "../../../types/key"; import { AttachmentData } from "../../models/data/attachment.data"; import { Attachment } from "../../models/domain/attachment"; @@ -64,10 +62,9 @@ describe("Attachment", () => { let encryptService: MockProxy; beforeEach(() => { - keyService = mock(); - encryptService = mock(); - - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); + const containerService = mockContainerService(); + keyService = containerService.keyService as MockProxy; + encryptService = containerService.encryptService as MockProxy; }); it("expected output", async () => { @@ -79,14 +76,13 @@ describe("Attachment", () => { attachment.key = mockEnc("key"); attachment.fileName = mockEnc("fileName"); - const userKey = new SymmetricCryptoKey(makeStaticByteArray(64)); - keyService.getUserKey.mockResolvedValue(userKey as UserKey); encryptService.decryptFileData.mockResolvedValue(makeStaticByteArray(32)); encryptService.unwrapSymmetricKey.mockResolvedValue( new SymmetricCryptoKey(makeStaticByteArray(64)), ); - const view = await attachment.decrypt(null); + const userKey = new SymmetricCryptoKey(makeStaticByteArray(64)); + const view = await attachment.decrypt(userKey); expect(view).toEqual({ id: "id", diff --git a/libs/common/src/vault/models/domain/card.spec.ts b/libs/common/src/vault/models/domain/card.spec.ts index a4d242329a4..bcef27d5cfd 100644 --- a/libs/common/src/vault/models/domain/card.spec.ts +++ b/libs/common/src/vault/models/domain/card.spec.ts @@ -1,4 +1,9 @@ -import { mockEnc, mockFromJson } from "../../../../spec"; +import { + makeSymmetricCryptoKey, + mockContainerService, + mockEnc, + mockFromJson, +} from "../../../../spec"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { CardData } from "../../../vault/models/data/card.data"; import { Card } from "../../models/domain/card"; @@ -58,7 +63,10 @@ describe("Card", () => { card.expYear = mockEnc("expYear"); card.code = mockEnc("code"); - const view = await card.decrypt(null); + const userKey = makeSymmetricCryptoKey(64); + + mockContainerService(); + const view = await card.decrypt(userKey); expect(view).toEqual({ _brand: "brand", diff --git a/libs/common/src/vault/models/domain/cipher.spec.ts b/libs/common/src/vault/models/domain/cipher.spec.ts index 1ef1449ef5c..abff95af8a2 100644 --- a/libs/common/src/vault/models/domain/cipher.spec.ts +++ b/libs/common/src/vault/models/domain/cipher.spec.ts @@ -2,9 +2,7 @@ import { mock } from "jest-mock-extended"; import { Jsonify } from "type-fest"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { KeyService } from "@bitwarden/key-management"; +import { MockProxy } from "@bitwarden/common/platform/spec/mock-deep"; import { CipherType as SdkCipherType, UriMatchType, @@ -14,11 +12,15 @@ import { EncString as SdkEncString, } from "@bitwarden/sdk-internal"; -import { makeStaticByteArray, mockEnc, mockFromJson } from "../../../../spec/utils"; +import { + makeStaticByteArray, + mockContainerService, + mockEnc, + mockFromJson, +} from "../../../../spec/utils"; import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service"; import { EncString } from "../../../key-management/crypto/models/enc-string"; import { UriMatchStrategy } from "../../../models/domain/domain-service"; -import { ContainerService } from "../../../platform/services/container.service"; import { InitializerKey } from "../../../platform/services/cryptography/initializer-key"; import { UserId } from "../../../types/guid"; import { CipherService } from "../../abstractions/cipher.service"; @@ -42,6 +44,13 @@ import { CipherPermissionsApi } from "../api/cipher-permissions.api"; const mockSymmetricKey = new SymmetricCryptoKey(makeStaticByteArray(64)); describe("Cipher DTO", () => { + let encryptService: MockProxy; + + beforeEach(() => { + const containerService = mockContainerService(); + encryptService = containerService.encryptService; + }); + it("Convert from empty CipherData", () => { const data = new CipherData(); const cipher = new Cipher(data); @@ -97,8 +106,6 @@ describe("Cipher DTO", () => { login.decrypt.mockResolvedValue(loginView); cipher.login = login; - const keyService = mock(); - const encryptService = mock(); const cipherService = mock(); encryptService.unwrapSymmetricKey.mockRejectedValue(new Error("Failed to unwrap key")); @@ -106,8 +113,6 @@ describe("Cipher DTO", () => { new SymmetricCryptoKey(makeStaticByteArray(64)), ); - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); - const cipherView = await cipher.decrypt( await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId), ); @@ -322,15 +327,10 @@ describe("Cipher DTO", () => { login.decrypt.mockResolvedValue(loginView); cipher.login = login; - const keyService = mock(); - const encryptService = mock(); - encryptService.unwrapSymmetricKey.mockResolvedValue( new SymmetricCryptoKey(makeStaticByteArray(64)), ); - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); - const cipherView = await cipher.decrypt(mockSymmetricKey); expect(cipherView).toMatchObject({ @@ -447,15 +447,10 @@ describe("Cipher DTO", () => { cipher.permissions = new CipherPermissionsApi(); cipher.archivedDate = undefined; - const keyService = mock(); - const encryptService = mock(); - encryptService.unwrapSymmetricKey.mockResolvedValue( new SymmetricCryptoKey(makeStaticByteArray(64)), ); - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); - const cipherView = await cipher.decrypt(mockSymmetricKey); expect(cipherView).toMatchObject({ @@ -590,15 +585,10 @@ describe("Cipher DTO", () => { card.decrypt.mockResolvedValue(cardView); cipher.card = card; - const keyService = mock(); - const encryptService = mock(); - encryptService.unwrapSymmetricKey.mockResolvedValue( new SymmetricCryptoKey(makeStaticByteArray(64)), ); - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); - const cipherView = await cipher.decrypt(mockSymmetricKey); expect(cipherView).toMatchObject({ @@ -757,15 +747,10 @@ describe("Cipher DTO", () => { identity.decrypt.mockResolvedValue(identityView); cipher.identity = identity; - const keyService = mock(); - const encryptService = mock(); - encryptService.unwrapSymmetricKey.mockResolvedValue( new SymmetricCryptoKey(makeStaticByteArray(64)), ); - (window as any).bitwardenContainerService = new ContainerService(keyService, encryptService); - const cipherView = await cipher.decrypt(mockSymmetricKey); expect(cipherView).toMatchObject({ diff --git a/libs/common/src/vault/models/domain/fido2-credential.spec.ts b/libs/common/src/vault/models/domain/fido2-credential.spec.ts index 3f43775433e..05504ea5666 100644 --- a/libs/common/src/vault/models/domain/fido2-credential.spec.ts +++ b/libs/common/src/vault/models/domain/fido2-credential.spec.ts @@ -1,4 +1,4 @@ -import { mockEnc } from "../../../../spec"; +import { makeSymmetricCryptoKey, mockContainerService, mockEnc } from "../../../../spec"; import { EncString } from "../../../key-management/crypto/models/enc-string"; import { EncryptionType } from "../../../platform/enums"; import { Fido2CredentialData } from "../data/fido2-credential.data"; @@ -103,7 +103,10 @@ describe("Fido2Credential", () => { credential.discoverable = mockEnc("true"); credential.creationDate = mockDate; - const credentialView = await credential.decrypt(null); + mockContainerService(); + + const cipherKey = makeSymmetricCryptoKey(64); + const credentialView = await credential.decrypt(cipherKey); expect(credentialView).toEqual({ credentialId: "credentialId", diff --git a/libs/common/src/vault/models/domain/field.spec.ts b/libs/common/src/vault/models/domain/field.spec.ts index d99336adad0..391e3a360ae 100644 --- a/libs/common/src/vault/models/domain/field.spec.ts +++ b/libs/common/src/vault/models/domain/field.spec.ts @@ -6,7 +6,7 @@ import { IdentityLinkedIdType, } from "@bitwarden/sdk-internal"; -import { mockEnc, mockFromJson } from "../../../../spec"; +import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { CardLinkedId, IdentityLinkedId, LoginLinkedId } from "../../enums"; import { FieldData } from "../../models/data/field.data"; @@ -22,6 +22,7 @@ describe("Field", () => { value: "encValue", linkedId: null, }; + mockContainerService(); }); it("Convert from empty", () => { diff --git a/libs/common/src/vault/models/domain/folder.spec.ts b/libs/common/src/vault/models/domain/folder.spec.ts index 4b1a9222b07..d9e9e265d91 100644 --- a/libs/common/src/vault/models/domain/folder.spec.ts +++ b/libs/common/src/vault/models/domain/folder.spec.ts @@ -1,6 +1,12 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { makeEncString, makeSymmetricCryptoKey, mockEnc, mockFromJson } from "../../../../spec"; +import { + makeEncString, + makeSymmetricCryptoKey, + mockContainerService, + mockEnc, + mockFromJson, +} from "../../../../spec"; import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { FolderData } from "../../models/data/folder.data"; @@ -15,6 +21,7 @@ describe("Folder", () => { name: "encName", revisionDate: "2022-01-31T12:00:00.000Z", }; + mockContainerService(); }); it("Convert", () => { diff --git a/libs/common/src/vault/models/domain/identity.spec.ts b/libs/common/src/vault/models/domain/identity.spec.ts index c2c2363fa0d..4ca51cad35f 100644 --- a/libs/common/src/vault/models/domain/identity.spec.ts +++ b/libs/common/src/vault/models/domain/identity.spec.ts @@ -1,4 +1,4 @@ -import { mockEnc, mockFromJson } from "../../../../spec"; +import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { IdentityData } from "../../models/data/identity.data"; import { Identity } from "../../models/domain/identity"; @@ -27,6 +27,8 @@ describe("Identity", () => { passportNumber: "encpassportNumber", licenseNumber: "enclicenseNumber", }; + + mockContainerService(); }); it("Convert from empty", () => { diff --git a/libs/common/src/vault/models/domain/login-uri.spec.ts b/libs/common/src/vault/models/domain/login-uri.spec.ts index b3893dcc76c..bc2d7999cf4 100644 --- a/libs/common/src/vault/models/domain/login-uri.spec.ts +++ b/libs/common/src/vault/models/domain/login-uri.spec.ts @@ -3,7 +3,7 @@ import { Jsonify } from "type-fest"; import { UriMatchType } from "@bitwarden/sdk-internal"; -import { mockEnc, mockFromJson } from "../../../../spec"; +import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service"; import { EncString } from "../../../key-management/crypto/models/enc-string"; import { UriMatchStrategy } from "../../../models/domain/domain-service"; @@ -20,6 +20,8 @@ describe("LoginUri", () => { uriChecksum: "encUriChecksum", match: UriMatchStrategy.Domain, }; + + mockContainerService(); }); it("Convert from empty", () => { diff --git a/libs/common/src/vault/models/domain/login-uri.ts b/libs/common/src/vault/models/domain/login-uri.ts index af3630a8b6e..b59a7df2d95 100644 --- a/libs/common/src/vault/models/domain/login-uri.ts +++ b/libs/common/src/vault/models/domain/login-uri.ts @@ -46,10 +46,10 @@ export class LoginUri extends Domain { return false; } - const keyService = Utils.getContainerService().getEncryptService(); - const localChecksum = await keyService.hash(clearTextUri, "sha256"); + const encryptService = Utils.getContainerService().getEncryptService(); + const localChecksum = await encryptService.hash(clearTextUri, "sha256"); - const remoteChecksum = await this.uriChecksum.decrypt(null, encKey); + const remoteChecksum = await encryptService.decryptString(this.uriChecksum, encKey); return remoteChecksum === localChecksum; } diff --git a/libs/common/src/vault/models/domain/login.spec.ts b/libs/common/src/vault/models/domain/login.spec.ts index e4606ebd1de..099d52dfb77 100644 --- a/libs/common/src/vault/models/domain/login.spec.ts +++ b/libs/common/src/vault/models/domain/login.spec.ts @@ -1,6 +1,6 @@ import { MockProxy, mock } from "jest-mock-extended"; -import { mockEnc, mockFromJson } from "../../../../spec"; +import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { UriMatchStrategy } from "../../../models/domain/domain-service"; import { LoginData } from "../../models/data/login.data"; @@ -14,6 +14,10 @@ import { Fido2CredentialView } from "../view/fido2-credential.view"; import { Fido2Credential } from "./fido2-credential"; describe("Login DTO", () => { + beforeEach(() => { + mockContainerService(); + }); + it("Convert from empty LoginData", () => { const data = new LoginData(); const login = new Login(data); diff --git a/libs/common/src/vault/models/domain/password.spec.ts b/libs/common/src/vault/models/domain/password.spec.ts index 2e37c5e8375..583df0c745b 100644 --- a/libs/common/src/vault/models/domain/password.spec.ts +++ b/libs/common/src/vault/models/domain/password.spec.ts @@ -1,4 +1,4 @@ -import { mockEnc, mockFromJson } from "../../../../spec"; +import { mockContainerService, mockEnc, mockFromJson } from "../../../../spec"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; import { PasswordHistoryData } from "../../models/data/password-history.data"; import { Password } from "../../models/domain/password"; @@ -11,6 +11,7 @@ describe("Password", () => { password: "encPassword", lastUsedDate: "2022-01-31T12:00:00.000Z", }; + mockContainerService(); }); it("Convert from empty", () => { diff --git a/libs/common/src/vault/models/domain/secure-note.spec.ts b/libs/common/src/vault/models/domain/secure-note.spec.ts index 4c8e8d470ca..f5923a0fca0 100644 --- a/libs/common/src/vault/models/domain/secure-note.spec.ts +++ b/libs/common/src/vault/models/domain/secure-note.spec.ts @@ -1,3 +1,4 @@ +import { mockContainerService } from "../../../../spec"; import { SecureNoteType } from "../../enums"; import { SecureNoteData } from "../data/secure-note.data"; @@ -10,6 +11,8 @@ describe("SecureNote", () => { data = { type: SecureNoteType.Generic, }; + + mockContainerService(); }); it("Convert from empty", () => { diff --git a/libs/common/src/vault/models/domain/ssh-key.spec.ts b/libs/common/src/vault/models/domain/ssh-key.spec.ts index 38228e54a4a..ab2dc6be65b 100644 --- a/libs/common/src/vault/models/domain/ssh-key.spec.ts +++ b/libs/common/src/vault/models/domain/ssh-key.spec.ts @@ -1,6 +1,6 @@ import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; -import { mockEnc } from "../../../../spec"; +import { mockContainerService, mockEnc } from "../../../../spec"; import { SshKeyApi } from "../api/ssh-key.api"; import { SshKeyData } from "../data/ssh-key.data"; @@ -17,6 +17,8 @@ describe("Sshkey", () => { KeyFingerprint: "keyFingerprint", }), ); + + mockContainerService(); }); it("Convert", () => { diff --git a/libs/common/src/vault/services/cipher.service.spec.ts b/libs/common/src/vault/services/cipher.service.spec.ts index 85ce8bd0423..ff2e9814ac7 100644 --- a/libs/common/src/vault/services/cipher.service.spec.ts +++ b/libs/common/src/vault/services/cipher.service.spec.ts @@ -55,7 +55,7 @@ const ENCRYPTED_BYTES = mock(); const cipherData: CipherData = { id: "id", - organizationId: "orgId", + organizationId: "4ff8c0b2-1d3e-4f8c-9b2d-1d3e4f8c0b2" as OrganizationId, folderId: "folderId", edit: true, viewPassword: true, @@ -119,6 +119,8 @@ describe("Cipher Service", () => { beforeEach(() => { encryptService.encryptFileData.mockReturnValue(Promise.resolve(ENCRYPTED_BYTES)); encryptService.encryptString.mockReturnValue(Promise.resolve(new EncString(ENCRYPTED_TEXT))); + keyService.orgKeys$.mockReturnValue(of({ [orgId]: makeSymmetricCryptoKey(32) as OrgKey })); + keyService.userKey$.mockReturnValue(of(makeSymmetricCryptoKey(64) as UserKey)); // Mock i18nService collator i18nService.collator = { @@ -181,9 +183,6 @@ describe("Cipher Service", () => { const testCipher = new Cipher(cipherData); const expectedRevisionDate = "2022-01-31T12:00:00.000Z"; - keyService.getOrgKey.mockReturnValue( - Promise.resolve(new SymmetricCryptoKey(new Uint8Array(32)) as OrgKey), - ); keyService.makeDataEncKey.mockReturnValue( Promise.resolve([ new SymmetricCryptoKey(new Uint8Array(32)),