From 9802add86b4ce0d4ecfcdba7ff59111e5fe15ff5 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:30:12 -0700 Subject: [PATCH] add tests --- .../default-change-password.service.spec.ts | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 libs/auth/src/common/services/change-password/default-change-password.service.spec.ts diff --git a/libs/auth/src/common/services/change-password/default-change-password.service.spec.ts b/libs/auth/src/common/services/change-password/default-change-password.service.spec.ts new file mode 100644 index 00000000000..b4e9cddbc32 --- /dev/null +++ b/libs/auth/src/common/services/change-password/default-change-password.service.spec.ts @@ -0,0 +1,115 @@ +import { mock, MockProxy } from "jest-mock-extended"; + +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; +import { KeyService } from "@bitwarden/key-management"; + +import { ChangePasswordService } from "../../abstractions"; + +import { DefaultChangePasswordService } from "./default-change-password.service"; + +describe("DefaultChangePasswordService", () => { + const userId = "userId" as UserId; + + let accountService: FakeAccountService; + let keyService: MockProxy; + let masterPasswordApiService: MockProxy; + let masterPasswordService: MockProxy; + + let sut: ChangePasswordService; + + const currentMasterKey = new SymmetricCryptoKey(new Uint8Array(32)) as MasterKey; + const currentServerMasterKeyHash = "currentServerMasterKeyHash"; + + const newPasswordHint = "newPasswordHint"; + const newMasterKey = new SymmetricCryptoKey(new Uint8Array(32)) as MasterKey; + const newServerMasterKeyHash = "newServerMasterKeyHash"; + + const decryptedUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; + const newMasterKeyEncryptedUserKey: [UserKey, EncString] = [ + decryptedUserKey, + { encryptedString: "newMasterKeyEncryptedUserKey" } as EncString, + ]; + + beforeEach(() => { + accountService = mockAccountServiceWith(userId); + keyService = mock(); + masterPasswordApiService = mock(); + masterPasswordService = mock(); + + sut = new DefaultChangePasswordService( + accountService, + keyService, + masterPasswordApiService, + masterPasswordService, + ); + + masterPasswordService.decryptUserKeyWithMasterKey.mockResolvedValue(decryptedUserKey); + keyService.encryptUserKeyWithMasterKey.mockResolvedValue(newMasterKeyEncryptedUserKey); + }); + + describe("changePassword()", () => { + it("should call the postPassword() API method with a the correct PasswordRequest credentials", async () => { + // Act + await sut.changePassword( + currentMasterKey, + currentServerMasterKeyHash, + newPasswordHint, + newMasterKey, + newServerMasterKeyHash, + ); + + // Assert + expect(masterPasswordApiService.postPassword).toHaveBeenCalledWith( + expect.objectContaining({ + masterPasswordHash: currentServerMasterKeyHash, + masterPasswordHint: newPasswordHint, + newMasterPasswordHash: newServerMasterKeyHash, + key: newMasterKeyEncryptedUserKey[1].encryptedString, + }), + ); + }); + + it("should call decryptUserKeyWithMasterKey and encryptUserKeyWithMasterKey", async () => { + // Act + await sut.changePassword( + currentMasterKey, + currentServerMasterKeyHash, + newPasswordHint, + newMasterKey, + newServerMasterKeyHash, + ); + + // Assert + expect(masterPasswordService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith( + currentMasterKey, + userId, + ); + expect(keyService.encryptUserKeyWithMasterKey).toHaveBeenCalledWith( + newMasterKey, + decryptedUserKey, + ); + }); + + it("should throw an error if user key decryption fails", async () => { + // Arrange + masterPasswordService.decryptUserKeyWithMasterKey.mockResolvedValue(null); + + // Act & Assert + await expect( + sut.changePassword( + currentMasterKey, + currentServerMasterKeyHash, + newPasswordHint, + newMasterKey, + newServerMasterKeyHash, + ), + ).rejects.toThrow("Could not decrypt user key"); + }); + }); +});