1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-09 13:10:17 +00:00

increase test coverage of DefaultChangePasswordService

This commit is contained in:
rr-bw
2025-04-24 16:01:56 -07:00
parent df8205f361
commit fad4a5c158

View File

@@ -1,5 +1,6 @@
import { mock, MockProxy } from "jest-mock-extended";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
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";
@@ -8,19 +9,28 @@ import { UserId } from "@bitwarden/common/types/guid";
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
import { KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management";
import { PasswordInputResult } from "../input-password/password-input-result";
import { ChangePasswordService } from "./change-password.service.abstraction";
import { DefaultChangePasswordService } from "./default-change-password.service";
describe("DefaultChangePasswordService", () => {
const userId = "userId" as UserId;
let keyService: MockProxy<KeyService>;
let masterPasswordApiService: MockProxy<MasterPasswordApiService>;
let masterPasswordService: MockProxy<InternalMasterPasswordServiceAbstraction>;
let sut: ChangePasswordService;
const inputPasswordResult = {
const userId = "userId" as UserId;
const user: Account = {
id: userId,
email: "email",
emailVerified: false,
name: "name",
};
const passwordInputResult: PasswordInputResult = {
currentMasterKey: new SymmetricCryptoKey(new Uint8Array(32)) as MasterKey,
currentServerMasterKeyHash: "currentServerMasterKeyHash",
@@ -57,14 +67,14 @@ describe("DefaultChangePasswordService", () => {
describe("changePassword()", () => {
it("should call the postPassword() API method with a the correct PasswordRequest credentials", async () => {
// Act
await sut.changePassword(inputPasswordResult, userId);
await sut.changePassword(passwordInputResult, userId);
// Assert
expect(masterPasswordApiService.postPassword).toHaveBeenCalledWith(
expect.objectContaining({
masterPasswordHash: inputPasswordResult.currentServerMasterKeyHash,
masterPasswordHint: inputPasswordResult.newPasswordHint,
newMasterPasswordHash: inputPasswordResult.newServerMasterKeyHash,
masterPasswordHash: passwordInputResult.currentServerMasterKeyHash,
masterPasswordHint: passwordInputResult.newPasswordHint,
newMasterPasswordHash: passwordInputResult.newServerMasterKeyHash,
key: newMasterKeyEncryptedUserKey[1].encryptedString,
}),
);
@@ -72,26 +82,107 @@ describe("DefaultChangePasswordService", () => {
it("should call decryptUserKeyWithMasterKey and encryptUserKeyWithMasterKey", async () => {
// Act
await sut.changePassword(inputPasswordResult, userId);
await sut.changePassword(passwordInputResult, userId);
// Assert
expect(masterPasswordService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(
inputPasswordResult.currentMasterKey,
passwordInputResult.currentMasterKey,
userId,
);
expect(keyService.encryptUserKeyWithMasterKey).toHaveBeenCalledWith(
inputPasswordResult.newMasterKey,
passwordInputResult.newMasterKey,
decryptedUserKey,
);
});
it("should throw if a userId was not found", async () => {
// Arrange
const userId: null = null;
// Act
const testFn = sut.changePassword(passwordInputResult, userId);
// Assert
await expect(testFn).rejects.toThrow("userId not found");
});
it("should throw if a currentMasterKey was not found", async () => {
// Arrange
const incorrectPasswordInputResult = { ...passwordInputResult };
incorrectPasswordInputResult.currentMasterKey = null;
// Act
const testFn = sut.changePassword(incorrectPasswordInputResult, userId);
// Assert
await expect(testFn).rejects.toThrow(
"currentMasterKey or currentServerMasterKeyHash not found",
);
});
it("should throw if a currentServerMasterKeyHash was not found", async () => {
// Arrange
const incorrectPasswordInputResult = { ...passwordInputResult };
incorrectPasswordInputResult.currentServerMasterKeyHash = null;
// Act
const testFn = sut.changePassword(incorrectPasswordInputResult, userId);
// Assert
await expect(testFn).rejects.toThrow(
"currentMasterKey or currentServerMasterKeyHash not found",
);
});
it("should throw an error if user key decryption fails", async () => {
// Arrange
masterPasswordService.decryptUserKeyWithMasterKey.mockResolvedValue(null);
// Act & Assert
await expect(sut.changePassword(inputPasswordResult, userId)).rejects.toThrow(
"Could not decrypt user key",
// Act
const testFn = sut.changePassword(passwordInputResult, userId);
// Assert
await expect(testFn).rejects.toThrow("Could not decrypt user key");
});
it("should throw an error if postPassword() fails", async () => {
// Arrange
masterPasswordApiService.postPassword.mockRejectedValueOnce(new Error("error"));
// Act
const testFn = sut.changePassword(passwordInputResult, userId);
// Assert
await expect(testFn).rejects.toThrow("Could not change password");
expect(masterPasswordApiService.postPassword).toHaveBeenCalled();
});
});
describe("rotateUserKeyMasterPasswordAndEncryptedData()", () => {
it("should throw an error (the method is only implemented in Web)", async () => {
// Act
const testFn = sut.rotateUserKeyMasterPasswordAndEncryptedData(
"currentPassword",
"newPassword",
user,
"newPasswordHint",
);
// Assert
await expect(testFn).rejects.toThrow(
"rotateUserKeyMasterPasswordAndEncryptedData() is only implemented in Web",
);
});
});
describe("rotateUserKeyAndEncryptedDataLegacy()", () => {
it("should throw an error (the method is only implemented in Web)", async () => {
// Act
const testFn = sut.rotateUserKeyAndEncryptedDataLegacy("newPassword", user);
// Assert
await expect(testFn).rejects.toThrow(
"rotateUserKeyAndEncryptedDataLegacy() is only implemented in Web",
);
});
});