1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00

[Pm-13097] Rename cryptoservice to keyservice and move it to km ownership (#11358)

* Rename cryptoservice to keyservice

* Rename cryptoservice to keyservice

* Move key service to key management ownership

* Remove accidentally added file

* Fix cli build

* Fix browser build

* Run prettier

* Fix builds

* Fix cli build

* Fix tests

* Fix incorrect renames

* Rename webauthn-login-crypto-service

* Fix build errors due to merge conflicts

* Fix linting
This commit is contained in:
Bernd Schoolmann
2024-10-24 19:41:30 +02:00
committed by GitHub
parent 554171b688
commit b486fcc689
229 changed files with 1385 additions and 1446 deletions

View File

@@ -3,7 +3,7 @@ import { PrfKey } from "../../../types/key";
/**
* Contains methods for all crypto operations specific to the WebAuthn login flow.
*/
export abstract class WebAuthnLoginPrfCryptoServiceAbstraction {
export abstract class WebAuthnLoginPrfKeyServiceAbstraction {
/**
* Get the salt used to generate the PRF-output used when logging in with WebAuthn.
*/

View File

@@ -1,6 +1,7 @@
import { MockProxy, mock } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import {
FakeAccountService,
makeStaticByteArray,
@@ -8,7 +9,6 @@ import {
trackEmissions,
} from "../../../spec";
import { ApiService } from "../../abstractions/api.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { MessagingService } from "../../platform/abstractions/messaging.service";
import { StateService } from "../../platform/abstractions/state.service";
import { Utils } from "../../platform/misc/utils";
@@ -25,7 +25,7 @@ describe("AuthService", () => {
let accountService: FakeAccountService;
let messagingService: MockProxy<MessagingService>;
let cryptoService: MockProxy<CryptoService>;
let keyService: MockProxy<KeyService>;
let apiService: MockProxy<ApiService>;
let stateService: MockProxy<StateService>;
let tokenService: MockProxy<TokenService>;
@@ -36,7 +36,7 @@ describe("AuthService", () => {
beforeEach(() => {
accountService = mockAccountServiceWith(userId);
messagingService = mock();
cryptoService = mock();
keyService = mock();
apiService = mock();
stateService = mock();
tokenService = mock();
@@ -44,7 +44,7 @@ describe("AuthService", () => {
sut = new AuthService(
accountService,
messagingService,
cryptoService,
keyService,
apiService,
stateService,
tokenService,
@@ -63,7 +63,7 @@ describe("AuthService", () => {
beforeEach(() => {
accountService.activeAccountSubject.next(accountInfo);
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
});
it("emits LoggedOut when there is no active account", async () => {
@@ -84,7 +84,7 @@ describe("AuthService", () => {
it("emits LoggedOut when there is no access token but has a user key", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(false));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
expect(await firstValueFrom(sut.activeAccountStatus$)).toEqual(
AuthenticationStatus.LoggedOut,
@@ -93,14 +93,14 @@ describe("AuthService", () => {
it("emits Locked when there is an access token and no user key", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
expect(await firstValueFrom(sut.activeAccountStatus$)).toEqual(AuthenticationStatus.Locked);
});
it("emits Unlocked when there is an access token and user key", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
expect(await firstValueFrom(sut.activeAccountStatus$)).toEqual(AuthenticationStatus.Unlocked);
});
@@ -117,7 +117,7 @@ describe("AuthService", () => {
const emissions = trackEmissions(sut.activeAccountStatus$);
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
accountService.activeAccountSubject.next(accountInfo2);
expect(emissions).toEqual([AuthenticationStatus.Locked, AuthenticationStatus.Unlocked]);
@@ -150,7 +150,7 @@ describe("AuthService", () => {
describe("authStatusFor$", () => {
beforeEach(() => {
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
});
it.each([null, undefined, "not a userId"])(
@@ -172,14 +172,14 @@ describe("AuthService", () => {
it("emits Locked when there is an access token and no user key", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(undefined));
expect(await firstValueFrom(sut.authStatusFor$(userId))).toEqual(AuthenticationStatus.Locked);
});
it("emits Unlocked when there is an access token and user key", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(true));
cryptoService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
keyService.getInMemoryUserKeyFor$.mockReturnValue(of(userKey));
expect(await firstValueFrom(sut.authStatusFor$(userId))).toEqual(
AuthenticationStatus.Unlocked,

View File

@@ -9,8 +9,8 @@ import {
switchMap,
} from "rxjs";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { ApiService } from "../../abstractions/api.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { StateService } from "../../platform/abstractions/state.service";
import { MessageSender } from "../../platform/messaging";
import { Utils } from "../../platform/misc/utils";
@@ -27,7 +27,7 @@ export class AuthService implements AuthServiceAbstraction {
constructor(
protected accountService: AccountService,
protected messageSender: MessageSender,
protected cryptoService: CryptoService,
protected keyService: KeyService,
protected apiService: ApiService,
protected stateService: StateService,
private tokenService: TokenService,
@@ -69,7 +69,7 @@ export class AuthService implements AuthServiceAbstraction {
}
return combineLatest([
this.cryptoService.getInMemoryUserKeyFor$(userId),
this.keyService.getInMemoryUserKeyFor$(userId),
this.tokenService.hasAccessToken$(userId),
]).pipe(
map(([userKey, hasAccessToken]) => {

View File

@@ -2,10 +2,10 @@ import { firstValueFrom, map, Observable } from "rxjs";
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { AppIdService } from "../../platform/abstractions/app-id.service";
import { ConfigService } from "../../platform/abstractions/config/config.service";
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
@@ -64,7 +64,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
constructor(
private keyGenerationService: KeyGenerationService,
private cryptoFunctionService: CryptoFunctionService,
private cryptoService: CryptoService,
private keyService: KeyService,
private encryptService: EncryptService,
private appIdService: AppIdService,
private devicesApiService: DevicesApiServiceAbstraction,
@@ -124,7 +124,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
}
// Attempt to get user key
const userKey: UserKey = await this.cryptoService.getUserKey(userId);
const userKey: UserKey = await this.keyService.getUserKey(userId);
// If user key is not found, throw error
if (!userKey) {
@@ -187,7 +187,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction {
}
// At this point of rotating their keys, they should still have their old user key in state
const oldUserKey = await firstValueFrom(this.cryptoService.userKey$(userId));
const oldUserKey = await firstValueFrom(this.keyService.userKey$(userId));
const deviceIdentifier = await this.appIdService.getAppId();
const secretVerificationRequest = new SecretVerificationRequest();

View File

@@ -4,6 +4,7 @@ import { BehaviorSubject, of } from "rxjs";
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { UserDecryptionOptions } from "../../../../auth/src/common/models/domain/user-decryption-options";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-account-service";
import { FakeActiveUserState } from "../../../spec/fake-state";
import { FakeStateProvider } from "../../../spec/fake-state-provider";
@@ -11,7 +12,6 @@ import { DeviceType } from "../../enums";
import { AppIdService } from "../../platform/abstractions/app-id.service";
import { ConfigService } from "../../platform/abstractions/config/config.service";
import { CryptoFunctionService } from "../../platform/abstractions/crypto-function.service";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
@@ -43,7 +43,7 @@ describe("deviceTrustService", () => {
const keyGenerationService = mock<KeyGenerationService>();
const cryptoFunctionService = mock<CryptoFunctionService>();
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const appIdService = mock<AppIdService>();
const devicesApiService = mock<DevicesApiServiceAbstraction>();
@@ -368,7 +368,7 @@ describe("deviceTrustService", () => {
.mockResolvedValue(mockDeviceRsaKeyPair);
cryptoSvcGetUserKeySpy = jest
.spyOn(cryptoService, "getUserKey")
.spyOn(keyService, "getUserKey")
.mockResolvedValue(mockUserKey);
cryptoSvcRsaEncryptSpy = jest
@@ -623,7 +623,7 @@ describe("deviceTrustService", () => {
const fakeNewUserKeyData = new Uint8Array(64);
fakeNewUserKeyData.fill(FakeNewUserKeyMarker, 0, 1);
fakeNewUserKey = new SymmetricCryptoKey(fakeNewUserKeyData) as UserKey;
cryptoService.userKey$.mockReturnValue(of(fakeNewUserKey));
keyService.userKey$.mockReturnValue(of(fakeNewUserKey));
});
it("throws an error when a null user id is passed in", async () => {
@@ -659,7 +659,7 @@ describe("deviceTrustService", () => {
fakeOldUserKeyData.fill(FakeOldUserKeyMarker, 0, 1);
// Mock the retrieval of a user key that differs from the new one passed into the method
cryptoService.userKey$.mockReturnValue(
keyService.userKey$.mockReturnValue(
of(new SymmetricCryptoKey(fakeOldUserKeyData) as UserKey),
);
@@ -749,7 +749,7 @@ describe("deviceTrustService", () => {
return new DeviceTrustService(
keyGenerationService,
cryptoFunctionService,
cryptoService,
keyService,
encryptService,
appIdService,
devicesApiService,

View File

@@ -1,12 +1,12 @@
import { mock } from "jest-mock-extended";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../spec";
import { ApiService } from "../../abstractions/api.service";
import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationData } from "../../admin-console/models/data/organization.data";
import { Organization } from "../../admin-console/models/domain/organization";
import { ProfileOrganizationResponse } from "../../admin-console/models/response/profile-organization.response";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { LogService } from "../../platform/abstractions/log.service";
import { Utils } from "../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key";
@@ -27,7 +27,7 @@ import { TokenService } from "./token.service";
describe("KeyConnectorService", () => {
let keyConnectorService: KeyConnectorService;
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const apiService = mock<ApiService>();
const tokenService = mock<TokenService>();
const logService = mock<LogService>();
@@ -56,7 +56,7 @@ describe("KeyConnectorService", () => {
keyConnectorService = new KeyConnectorService(
accountService,
masterPasswordService,
cryptoService,
keyService,
apiService,
tokenService,
logService,

View File

@@ -2,12 +2,12 @@ import { firstValueFrom } from "rxjs";
import { LogoutReason } from "@bitwarden/auth/common";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { ApiService } from "../../abstractions/api.service";
import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationUserType } from "../../admin-console/enums";
import { Organization } from "../../admin-console/models/domain/organization";
import { KeysRequest } from "../../models/request/keys.request";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
import { LogService } from "../../platform/abstractions/log.service";
import { KdfType } from "../../platform/enums/kdf-type.enum";
@@ -54,7 +54,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
constructor(
private accountService: AccountService,
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
private cryptoService: CryptoService,
private keyService: KeyService,
private apiService: ApiService,
private tokenService: TokenService,
private logService: LogService,
@@ -146,7 +146,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
? new PBKDF2KdfConfig(kdfIterations)
: new Argon2KdfConfig(kdfIterations, kdfMemory, kdfParallelism);
const masterKey = await this.cryptoService.makeMasterKey(
const masterKey = await this.keyService.makeMasterKey(
password.keyB64,
await this.tokenService.getEmail(),
kdfConfig,
@@ -154,11 +154,11 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
await this.masterPasswordService.setMasterKey(masterKey, userId);
const userKey = await this.cryptoService.makeUserKey(masterKey);
await this.cryptoService.setUserKey(userKey[0], userId);
await this.cryptoService.setMasterKeyEncryptedUserKey(userKey[1].encryptedString, userId);
const userKey = await this.keyService.makeUserKey(masterKey);
await this.keyService.setUserKey(userKey[0], userId);
await this.keyService.setMasterKeyEncryptedUserKey(userKey[1].encryptedString, userId);
const [pubKey, privKey] = await this.cryptoService.makeKeyPair(userKey[0]);
const [pubKey, privKey] = await this.keyService.makeKeyPair(userKey[0]);
try {
const keyConnectorUrl =

View File

@@ -5,9 +5,9 @@ import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { UserId } from "../../../../common/src/types/guid";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { OrganizationApiServiceAbstraction } from "../../admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationAutoEnrollStatusResponse } from "../../admin-console/models/response/organization-auto-enroll-status.response";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { AccountInfo, AccountService } from "../abstractions/account.service";
@@ -18,7 +18,7 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
let organizationApiService: MockProxy<OrganizationApiServiceAbstraction>;
let accountService: MockProxy<AccountService>;
let cryptoService: MockProxy<CryptoService>;
let keyService: MockProxy<KeyService>;
let encryptService: MockProxy<EncryptService>;
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
let i18nService: MockProxy<I18nService>;
@@ -28,14 +28,14 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
organizationApiService = mock<OrganizationApiServiceAbstraction>();
accountService = mock<AccountService>();
accountService.activeAccount$ = activeAccountSubject;
cryptoService = mock<CryptoService>();
keyService = mock<KeyService>();
encryptService = mock<EncryptService>();
organizationUserApiService = mock<OrganizationUserApiService>();
i18nService = mock<I18nService>();
service = new PasswordResetEnrollmentServiceImplementation(
organizationApiService,
accountService,
cryptoService,
keyService,
encryptService,
organizationUserApiService,
i18nService,
@@ -99,7 +99,7 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
};
activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId }));
cryptoService.getUserKey.mockResolvedValue({ key: "key" } as any);
keyService.getUserKey.mockResolvedValue({ key: "key" } as any);
encryptService.rsaEncrypt.mockResolvedValue(encryptedKey as any);
await service.enroll("orgId");

View File

@@ -6,8 +6,8 @@ import {
} from "@bitwarden/admin-console/common";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { KeyService } from "../../../../key-management/src/abstractions/key.service";
import { OrganizationApiServiceAbstraction } from "../../admin-console/abstractions/organization/organization-api.service.abstraction";
import { CryptoService } from "../../platform/abstractions/crypto.service";
import { I18nService } from "../../platform/abstractions/i18n.service";
import { Utils } from "../../platform/misc/utils";
import { UserKey } from "../../types/key";
@@ -20,7 +20,7 @@ export class PasswordResetEnrollmentServiceImplementation
constructor(
protected organizationApiService: OrganizationApiServiceAbstraction,
protected accountService: AccountService,
protected cryptoService: CryptoService,
protected keyService: KeyService,
protected encryptService: EncryptService,
protected organizationUserApiService: OrganizationUserApiService,
protected i18nService: I18nService,
@@ -47,7 +47,7 @@ export class PasswordResetEnrollmentServiceImplementation
userId =
userId ?? (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))));
userKey = userKey ?? (await this.cryptoService.getUserKey(userId));
userKey = userKey ?? (await this.keyService.getUserKey(userId));
// RSA Encrypt user's userKey.key with organization public key
const encryptedKey = await this.encryptService.rsaEncrypt(userKey.key, orgPublicKey);

View File

@@ -8,9 +8,9 @@ import {
UserDecryptionOptionsServiceAbstraction,
} from "@bitwarden/auth/common";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { FakeAccountService, mockAccountServiceWith } from "../../../../spec";
import { VaultTimeoutSettingsService } from "../../../abstractions/vault-timeout/vault-timeout-settings.service";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { LogService } from "../../../platform/abstractions/log.service";
import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service";
@@ -31,7 +31,7 @@ import { UserVerificationService } from "./user-verification.service";
describe("UserVerificationService", () => {
let sut: UserVerificationService;
const cryptoService = mock<CryptoService>();
const keyService = mock<KeyService>();
const masterPasswordService = mock<InternalMasterPasswordServiceAbstraction>();
const i18nService = mock<I18nService>();
const userVerificationApiService = mock<UserVerificationApiServiceAbstraction>();
@@ -50,7 +50,7 @@ describe("UserVerificationService", () => {
accountService = mockAccountServiceWith(mockUserId);
sut = new UserVerificationService(
cryptoService,
keyService,
accountService,
masterPasswordService,
i18nService,
@@ -132,7 +132,7 @@ describe("UserVerificationService", () => {
setMasterPasswordAvailability(false);
setPinAvailability("DISABLED");
vaultTimeoutSettingsService.isBiometricLockSet.mockResolvedValue(isBiometricsLockSet);
cryptoService.hasUserKeyStored.mockResolvedValue(isBiometricsUserKeyStored);
keyService.hasUserKeyStored.mockResolvedValue(isBiometricsUserKeyStored);
platformUtilsService.supportsSecureStorage.mockReturnValue(platformSupportSecureStorage);
const result = await sut.getAvailableVerificationOptions("client");
@@ -205,7 +205,7 @@ describe("UserVerificationService", () => {
kdfConfigService.getKdfConfig.mockResolvedValue("kdfConfig" as unknown as KdfConfig);
masterPasswordService.masterKey$.mockReturnValue(of("masterKey" as unknown as MasterKey));
cryptoService.hashMasterKey
keyService.hashMasterKey
.calledWith("password", "masterKey" as unknown as MasterKey, HashPurpose.LocalAuthorization)
.mockResolvedValue("localHash");
});
@@ -216,7 +216,7 @@ describe("UserVerificationService", () => {
});
it("returns if verification is successful", async () => {
cryptoService.compareAndUpdateKeyHash.mockResolvedValueOnce(true);
keyService.compareAndUpdateKeyHash.mockResolvedValueOnce(true);
const result = await sut.verifyUserByMasterPassword(
{
@@ -227,7 +227,7 @@ describe("UserVerificationService", () => {
"email",
);
expect(cryptoService.compareAndUpdateKeyHash).toHaveBeenCalled();
expect(keyService.compareAndUpdateKeyHash).toHaveBeenCalled();
expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith(
"localHash",
mockUserId,
@@ -240,7 +240,7 @@ describe("UserVerificationService", () => {
});
it("throws if verification fails", async () => {
cryptoService.compareAndUpdateKeyHash.mockResolvedValueOnce(false);
keyService.compareAndUpdateKeyHash.mockResolvedValueOnce(false);
await expect(
sut.verifyUserByMasterPassword(
@@ -253,7 +253,7 @@ describe("UserVerificationService", () => {
),
).rejects.toThrow("Invalid master password");
expect(cryptoService.compareAndUpdateKeyHash).toHaveBeenCalled();
expect(keyService.compareAndUpdateKeyHash).toHaveBeenCalled();
expect(masterPasswordService.setMasterKeyHash).not.toHaveBeenCalledWith();
expect(masterPasswordService.setMasterKey).not.toHaveBeenCalledWith();
});
@@ -265,7 +265,7 @@ describe("UserVerificationService", () => {
});
it("returns if verification is successful", async () => {
cryptoService.hashMasterKey
keyService.hashMasterKey
.calledWith(
"password",
"masterKey" as unknown as MasterKey,
@@ -285,7 +285,7 @@ describe("UserVerificationService", () => {
"email",
);
expect(cryptoService.compareAndUpdateKeyHash).not.toHaveBeenCalled();
expect(keyService.compareAndUpdateKeyHash).not.toHaveBeenCalled();
expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith(
"localHash",
mockUserId,
@@ -298,7 +298,7 @@ describe("UserVerificationService", () => {
});
it("throws if verification fails", async () => {
cryptoService.hashMasterKey
keyService.hashMasterKey
.calledWith(
"password",
"masterKey" as unknown as MasterKey,
@@ -318,7 +318,7 @@ describe("UserVerificationService", () => {
),
).rejects.toThrow("Invalid master password");
expect(cryptoService.compareAndUpdateKeyHash).not.toHaveBeenCalled();
expect(keyService.compareAndUpdateKeyHash).not.toHaveBeenCalled();
expect(masterPasswordService.setMasterKeyHash).not.toHaveBeenCalledWith();
expect(masterPasswordService.setMasterKey).not.toHaveBeenCalledWith();
});
@@ -380,7 +380,7 @@ describe("UserVerificationService", () => {
it("throws if master key cannot be created", async () => {
kdfConfigService.getKdfConfig.mockResolvedValueOnce("kdfConfig" as unknown as KdfConfig);
masterPasswordService.masterKey$.mockReturnValueOnce(of(null));
cryptoService.makeMasterKey.mockResolvedValueOnce(null);
keyService.makeMasterKey.mockResolvedValueOnce(null);
await expect(
sut.verifyUserByMasterPassword(

View File

@@ -3,8 +3,8 @@ import { firstValueFrom, map } from "rxjs";
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
import { PinServiceAbstraction } from "../../../../../auth/src/common/abstractions/pin.service.abstraction";
import { KeyService } from "../../../../../key-management/src/abstractions/key.service";
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "../../../abstractions/vault-timeout/vault-timeout-settings.service";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { LogService } from "../../../platform/abstractions/log.service";
import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service";
@@ -39,7 +39,7 @@ import {
*/
export class UserVerificationService implements UserVerificationServiceAbstraction {
constructor(
private cryptoService: CryptoService,
private keyService: KeyService,
private accountService: AccountService,
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
private i18nService: I18nService,
@@ -66,7 +66,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
this.hasMasterPasswordAndMasterKeyHash(userId),
this.pinService.isPinDecryptionAvailable(userId),
this.vaultTimeoutSettingsService.isBiometricLockSet(userId),
this.cryptoService.hasUserKeyStored(KeySuffixOptions.Biometric, userId),
this.keyService.hasUserKeyStored(KeySuffixOptions.Biometric, userId),
]);
// note: we do not need to check this.platformUtilsService.supportsBiometric() because
@@ -119,7 +119,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
);
let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
if (!masterKey && !alreadyHashed) {
masterKey = await this.cryptoService.makeMasterKey(
masterKey = await this.keyService.makeMasterKey(
verification.secret,
email,
await this.kdfConfigService.getKdfConfig(),
@@ -127,7 +127,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
}
request.masterPasswordHash = alreadyHashed
? verification.secret
: await this.cryptoService.hashMasterKey(verification.secret, masterKey);
: await this.keyService.hashMasterKey(verification.secret, masterKey);
}
return request;
@@ -196,7 +196,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
if (!masterKey) {
masterKey = await this.cryptoService.makeMasterKey(verification.secret, email, kdfConfig);
masterKey = await this.keyService.makeMasterKey(verification.secret, email, kdfConfig);
}
if (!masterKey) {
@@ -206,7 +206,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
let policyOptions: MasterPasswordPolicyResponse | null;
// Client-side verification
if (await this.hasMasterPasswordAndMasterKeyHash(userId)) {
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
const passwordValid = await this.keyService.compareAndUpdateKeyHash(
verification.secret,
masterKey,
);
@@ -217,7 +217,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
} else {
// Server-side verification
const request = new SecretVerificationRequest();
const serverKeyHash = await this.cryptoService.hashMasterKey(
const serverKeyHash = await this.keyService.hashMasterKey(
verification.secret,
masterKey,
HashPurpose.ServerAuthorization,
@@ -230,7 +230,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
}
}
const localKeyHash = await this.cryptoService.hashMasterKey(
const localKeyHash = await this.keyService.hashMasterKey(
verification.secret,
masterKey,
HashPurpose.LocalAuthorization,
@@ -254,7 +254,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
let userKey: UserKey;
// Biometrics crashes and doesn't return a value if the user cancels the prompt
try {
userKey = await this.cryptoService.getUserKeyFromStorage(KeySuffixOptions.Biometric);
userKey = await this.keyService.getUserKeyFromStorage(KeySuffixOptions.Biometric);
} catch (e) {
this.logService.error(`Biometrics User Verification failed: ${e.message}`);
// So, any failures should be treated as a failed verification

View File

@@ -2,15 +2,15 @@ import { mock, MockProxy } from "jest-mock-extended";
import { CryptoFunctionService } from "../../../platform/abstractions/crypto-function.service";
import { WebAuthnLoginPrfCryptoService } from "./webauthn-login-prf-crypto.service";
import { WebAuthnLoginPrfKeyService } from "./webauthn-login-prf-key.service";
describe("WebAuthnLoginPrfCryptoService", () => {
describe("WebAuthnLoginPrfKeyService", () => {
let cryptoFunctionService: MockProxy<CryptoFunctionService>;
let service: WebAuthnLoginPrfCryptoService;
let service: WebAuthnLoginPrfKeyService;
beforeEach(() => {
cryptoFunctionService = mock<CryptoFunctionService>();
service = new WebAuthnLoginPrfCryptoService(cryptoFunctionService);
service = new WebAuthnLoginPrfKeyService(cryptoFunctionService);
});
describe("createSymmetricKeyFromPrf", () => {

View File

@@ -1,11 +1,11 @@
import { CryptoFunctionService } from "../../../platform/abstractions/crypto-function.service";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
import { PrfKey } from "../../../types/key";
import { WebAuthnLoginPrfCryptoServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction";
import { WebAuthnLoginPrfKeyServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-key.service.abstraction";
const LoginWithPrfSalt = "passwordless-login";
export class WebAuthnLoginPrfCryptoService implements WebAuthnLoginPrfCryptoServiceAbstraction {
export class WebAuthnLoginPrfKeyService implements WebAuthnLoginPrfKeyServiceAbstraction {
constructor(private cryptoFunctionService: CryptoFunctionService) {}
async getLoginWithPrfSalt(): Promise<ArrayBuffer> {

View File

@@ -7,7 +7,7 @@ import { Utils } from "../../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
import { PrfKey } from "../../../types/key";
import { WebAuthnLoginApiServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-api.service.abstraction";
import { WebAuthnLoginPrfCryptoServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction";
import { WebAuthnLoginPrfKeyServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-key.service.abstraction";
import { AuthResult } from "../../models/domain/auth-result";
import { WebAuthnLoginCredentialAssertionOptionsView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion-options.view";
import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion.view";
@@ -21,7 +21,7 @@ describe("WebAuthnLoginService", () => {
const webAuthnLoginApiService = mock<WebAuthnLoginApiServiceAbstraction>();
const loginStrategyService = mock<LoginStrategyServiceAbstraction>();
const webAuthnLoginPrfCryptoService = mock<WebAuthnLoginPrfCryptoServiceAbstraction>();
const webAuthnLoginPrfKeyService = mock<WebAuthnLoginPrfKeyServiceAbstraction>();
const navigatorCredentials = mock<CredentialsContainer>();
const logService = mock<LogService>();
@@ -72,7 +72,7 @@ describe("WebAuthnLoginService", () => {
return new WebAuthnLoginService(
webAuthnLoginApiService,
loginStrategyService,
webAuthnLoginPrfCryptoService,
webAuthnLoginPrfKeyService,
window,
logService,
);
@@ -141,8 +141,8 @@ describe("WebAuthnLoginService", () => {
publicKeyCredential.getClientExtensionResults().prf?.results?.first;
const prfKey = new SymmetricCryptoKey(new Uint8Array(prfResult)) as PrfKey;
webAuthnLoginPrfCryptoService.getLoginWithPrfSalt.mockResolvedValue(saltArrayBuffer);
webAuthnLoginPrfCryptoService.createSymmetricKeyFromPrf.mockResolvedValue(prfKey);
webAuthnLoginPrfKeyService.getLoginWithPrfSalt.mockResolvedValue(saltArrayBuffer);
webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf.mockResolvedValue(prfKey);
// Mock implementations
navigatorCredentials.get.mockResolvedValue(publicKeyCredential);
@@ -152,7 +152,7 @@ describe("WebAuthnLoginService", () => {
// Assert
expect(webAuthnLoginPrfCryptoService.getLoginWithPrfSalt).toHaveBeenCalled();
expect(webAuthnLoginPrfKeyService.getLoginWithPrfSalt).toHaveBeenCalled();
expect(navigatorCredentials.get).toHaveBeenCalledWith(
expect.objectContaining({
@@ -169,9 +169,7 @@ describe("WebAuthnLoginService", () => {
}),
);
expect(webAuthnLoginPrfCryptoService.createSymmetricKeyFromPrf).toHaveBeenCalledWith(
prfResult,
);
expect(webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf).toHaveBeenCalledWith(prfResult);
expect(result).toBeInstanceOf(WebAuthnLoginCredentialAssertionView);
expect(result.token).toEqual(credentialAssertionOptions.token);

View File

@@ -3,7 +3,7 @@ import { LoginStrategyServiceAbstraction, WebAuthnLoginCredentials } from "@bitw
import { LogService } from "../../../platform/abstractions/log.service";
import { PrfKey } from "../../../types/key";
import { WebAuthnLoginApiServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-api.service.abstraction";
import { WebAuthnLoginPrfCryptoServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction";
import { WebAuthnLoginPrfKeyServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-key.service.abstraction";
import { WebAuthnLoginServiceAbstraction } from "../../abstractions/webauthn/webauthn-login.service.abstraction";
import { AuthResult } from "../../models/domain/auth-result";
import { WebAuthnLoginCredentialAssertionOptionsView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion-options.view";
@@ -17,7 +17,7 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction {
constructor(
private webAuthnLoginApiService: WebAuthnLoginApiServiceAbstraction,
private loginStrategyService: LoginStrategyServiceAbstraction,
private webAuthnLoginPrfCryptoService: WebAuthnLoginPrfCryptoServiceAbstraction,
private webAuthnLoginPrfKeyService: WebAuthnLoginPrfKeyServiceAbstraction,
private window: Window,
private logService?: LogService,
) {
@@ -37,7 +37,7 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction {
};
// TODO: Remove `any` when typescript typings add support for PRF
nativeOptions.publicKey.extensions = {
prf: { eval: { first: await this.webAuthnLoginPrfCryptoService.getLoginWithPrfSalt() } },
prf: { eval: { first: await this.webAuthnLoginPrfKeyService.getLoginWithPrfSalt() } },
} as any;
try {
@@ -50,7 +50,7 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction {
let symmetricPrfKey: PrfKey | undefined;
if (prfResult != undefined) {
symmetricPrfKey =
await this.webAuthnLoginPrfCryptoService.createSymmetricKeyFromPrf(prfResult);
await this.webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf(prfResult);
}
const deviceResponse = new WebAuthnLoginAssertionResponseRequest(response);