mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +00:00
feat(new SendPasswordService): [Auth/PM-23700] Create KM SendPasswordService (#15570)
* PM-23700 - SendPasswordService - create and test * PM-23700 - SendPassword Service comment clean up * PM-23700 - Use barrel file exports and register default service. * PM-23700 - DefaultSendPasswordService - work with Bernd to deliver better service
This commit is contained in:
@@ -169,6 +169,10 @@ import {
|
||||
MasterPasswordServiceAbstraction,
|
||||
} from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { MasterPasswordService } from "@bitwarden/common/key-management/master-password/services/master-password.service";
|
||||
import {
|
||||
SendPasswordService,
|
||||
DefaultSendPasswordService,
|
||||
} from "@bitwarden/common/key-management/sends";
|
||||
import {
|
||||
DefaultVaultTimeoutService,
|
||||
DefaultVaultTimeoutSettingsService,
|
||||
@@ -1502,6 +1506,11 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: DefaultCipherAuthorizationService,
|
||||
deps: [CollectionService, OrganizationServiceAbstraction, AccountServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: SendPasswordService,
|
||||
useClass: DefaultSendPasswordService,
|
||||
deps: [CryptoFunctionServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: LoginApprovalComponentServiceAbstraction,
|
||||
useClass: DefaultLoginApprovalComponentService,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./send-password.service";
|
||||
@@ -0,0 +1,17 @@
|
||||
import { SendHashedPassword, SendPasswordKeyMaterial } from "../types/send-hashed-password.type";
|
||||
|
||||
/**
|
||||
* Service for managing passwords for sends.
|
||||
*/
|
||||
export abstract class SendPasswordService {
|
||||
/**
|
||||
* Hashes a raw send password using the provided key material
|
||||
* @param password - the raw password to hash
|
||||
* @param keyMaterial - the key material
|
||||
* @returns a promise that resolves to the hashed password as a SendHashedPassword
|
||||
*/
|
||||
abstract hashPassword(
|
||||
password: string,
|
||||
keyMaterial: SendPasswordKeyMaterial,
|
||||
): Promise<SendHashedPassword>;
|
||||
}
|
||||
3
libs/common/src/key-management/sends/index.ts
Normal file
3
libs/common/src/key-management/sends/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./abstractions";
|
||||
export * from "./services";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,63 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { SEND_KDF_ITERATIONS } from "../../../tools/send/send-kdf";
|
||||
import { CryptoFunctionService } from "../../crypto/abstractions/crypto-function.service";
|
||||
import { SendPasswordKeyMaterial } from "../types";
|
||||
|
||||
import { DefaultSendPasswordService } from "./default-send-password.service";
|
||||
|
||||
describe("DefaultSendPasswordService", () => {
|
||||
let sendPasswordService: DefaultSendPasswordService;
|
||||
let mockCryptoFunctionService: MockProxy<CryptoFunctionService>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockCryptoFunctionService = mock<CryptoFunctionService>();
|
||||
|
||||
sendPasswordService = new DefaultSendPasswordService(mockCryptoFunctionService);
|
||||
});
|
||||
|
||||
it("instantiates", () => {
|
||||
expect(sendPasswordService).not.toBeFalsy();
|
||||
});
|
||||
|
||||
it("hashes a password with the provided key material", async () => {
|
||||
// Arrange
|
||||
const password = "testPassword";
|
||||
|
||||
const keyMaterial = new Uint8Array([1, 2, 3, 4, 5]) as SendPasswordKeyMaterial;
|
||||
|
||||
const expectedHash = new Uint8Array([1, 2, 3, 4, 5]); // Mocked hash output
|
||||
mockCryptoFunctionService.pbkdf2.mockResolvedValue(expectedHash);
|
||||
|
||||
// Act
|
||||
const result = await sendPasswordService.hashPassword(password, keyMaterial);
|
||||
|
||||
// Assert
|
||||
expect(mockCryptoFunctionService.pbkdf2).toHaveBeenCalledWith(
|
||||
password,
|
||||
keyMaterial,
|
||||
"sha256",
|
||||
SEND_KDF_ITERATIONS,
|
||||
);
|
||||
|
||||
expect(result).toEqual(expectedHash);
|
||||
});
|
||||
|
||||
it("throws an error if a password isn't provided", async () => {
|
||||
// Arrange
|
||||
const keyMaterial = new Uint8Array([1, 2, 3, 4, 5]) as SendPasswordKeyMaterial;
|
||||
const expectedError = new Error("Password and key material are required.");
|
||||
// Act & Assert
|
||||
await expect(sendPasswordService.hashPassword("", keyMaterial)).rejects.toThrow(expectedError);
|
||||
});
|
||||
|
||||
it("throws an error if key material isn't provided", async () => {
|
||||
// Arrange
|
||||
const password = "testPassword";
|
||||
const expectedError = new Error("Password and key material are required.");
|
||||
// Act & Assert
|
||||
await expect(
|
||||
sendPasswordService.hashPassword(password, undefined as unknown as SendPasswordKeyMaterial),
|
||||
).rejects.toThrow(expectedError);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { SEND_KDF_ITERATIONS } from "../../../tools/send/send-kdf";
|
||||
import { CryptoFunctionService } from "../../crypto/abstractions/crypto-function.service";
|
||||
import { SendPasswordService } from "../abstractions/send-password.service";
|
||||
import { SendHashedPassword, SendPasswordKeyMaterial } from "../types/send-hashed-password.type";
|
||||
|
||||
export class DefaultSendPasswordService implements SendPasswordService {
|
||||
constructor(private cryptoFunctionService: CryptoFunctionService) {}
|
||||
|
||||
async hashPassword(
|
||||
password: string,
|
||||
keyMaterial: SendPasswordKeyMaterial,
|
||||
): Promise<SendHashedPassword> {
|
||||
if (!password || !keyMaterial) {
|
||||
throw new Error("Password and key material are required.");
|
||||
}
|
||||
|
||||
// Derive a password hash using the key material.
|
||||
const passwordHash = await this.cryptoFunctionService.pbkdf2(
|
||||
password,
|
||||
keyMaterial,
|
||||
"sha256",
|
||||
SEND_KDF_ITERATIONS,
|
||||
);
|
||||
|
||||
return passwordHash as SendHashedPassword;
|
||||
}
|
||||
}
|
||||
1
libs/common/src/key-management/sends/services/index.ts
Normal file
1
libs/common/src/key-management/sends/services/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./default-send-password.service";
|
||||
1
libs/common/src/key-management/sends/types/index.ts
Normal file
1
libs/common/src/key-management/sends/types/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./send-hashed-password.type";
|
||||
@@ -0,0 +1,4 @@
|
||||
import { Opaque } from "type-fest";
|
||||
|
||||
export type SendHashedPassword = Opaque<Uint8Array, "SendHashedPassword">;
|
||||
export type SendPasswordKeyMaterial = Opaque<Uint8Array, "SendPasswordKeyMaterial">;
|
||||
Reference in New Issue
Block a user