diff --git a/libs/common/src/key-management/master-password/services/master-password.service.ts b/libs/common/src/key-management/master-password/services/master-password.service.ts index 23ef0860224..4aa6f8134c9 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.ts @@ -3,6 +3,7 @@ import { firstValueFrom, map, Observable } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { assertNonNullish } from "@bitwarden/common/auth/utils"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; // eslint-disable-next-line no-restricted-imports @@ -78,6 +79,14 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr private accountService: AccountService, ) {} + saltForUser$(userId: UserId): Observable { + assertNonNullish(userId, "userId"); + return this.accountService.accounts$.pipe( + map((accounts) => accounts[userId].email), + map((email) => this.emailToSalt(email)), + ); + } + masterKey$(userId: UserId): Observable { if (userId == null) { throw new Error("User ID is required."); @@ -239,15 +248,12 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr kdf: KdfConfig, salt: MasterPasswordSalt, ): Promise { - if (password == null) { - throw new Error("Password is required."); - } - if (kdf == null) { - throw new Error("KDF configuration is required."); - } - if (salt == null) { - throw new Error("Salt is required."); - } + assertNonNullish(password, "password"); + assertNonNullish(kdf, "kdf"); + assertNonNullish(salt, "salt"); + + // We don't trust callers to use masterpasswordsalt correctly. They may type assert incorrectly. + salt = salt.toLowerCase().trim() as MasterPasswordSalt; const SERVER_AUTHENTICATION_HASH_ITERATIONS = 1; @@ -279,18 +285,13 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr salt: MasterPasswordSalt, userKey: UserKey, ): Promise { - if (password == null) { - throw new Error("Password is required."); - } - if (kdf == null) { - throw new Error("KDF configuration is required."); - } - if (salt == null) { - throw new Error("Salt is required."); - } - if (userKey == null) { - throw new Error("User key is required."); - } + assertNonNullish(password, "password"); + assertNonNullish(kdf, "kdf"); + assertNonNullish(salt, "salt"); + assertNonNullish(userKey, "userKey"); + + // We don't trust callers to use masterpasswordsalt correctly. They may type assert incorrectly. + salt = salt.toLowerCase().trim() as MasterPasswordSalt; await SdkLoadService.Ready; const masterKeyWrappedUserKey = new EncString( @@ -312,12 +313,8 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr password: string, masterPasswordUnlockData: MasterPasswordUnlockData, ): Promise { - if (password == null) { - throw new Error("Password is required."); - } - if (masterPasswordUnlockData == null) { - throw new Error("Master password unlock data is required."); - } + assertNonNullish(password, "password"); + assertNonNullish(masterPasswordUnlockData, "masterPasswordUnlockData"); await SdkLoadService.Ready; const userKey = new SymmetricCryptoKey( diff --git a/libs/common/src/types/key.ts b/libs/common/src/types/key.ts index 4ecf947fb6c..8984452e701 100644 --- a/libs/common/src/types/key.ts +++ b/libs/common/src/types/key.ts @@ -6,7 +6,7 @@ import { SymmetricCryptoKey } from "../platform/models/domain/symmetric-crypto-k export type DeviceKey = Opaque; export type PrfKey = Opaque; export type UserKey = Opaque; -/** @deprecated The master key is not meant to be interacted with directly. Consider using an API from masterpasswordservice instead */ +/** @deprecated Interacting with the master key directly is prohibited. Use a high level function from MasterPasswordService instead. */ export type MasterKey = Opaque; export type PinKey = Opaque; export type OrgKey = Opaque; diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index 9573e093279..008c97c358d 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -150,13 +150,16 @@ export abstract class KeyService { /** * Generates a new user key + * @deprecated Interacting with the master key directly is prohibited. Use {@link makeUserKey} instead. * @throws Error when master key is null and there is no active user * @param masterKey The user's master key. When null, grabs master key from active user. * @returns A new user key and the master key protected version of it */ abstract makeUserKey(masterKey: MasterKey | null): Promise<[UserKey, EncString]>; /** - * Generates a new v1 user key + * Generates a new user key for a V1 user + * Note: This will be replaced by a higher level function to initialize a whole users cryptographic state in the near future. + * @returns A new user key */ abstract makeUserKeyV1(): Promise; /** @@ -169,13 +172,14 @@ export abstract class KeyService { /** * @deprecated * @throws Error when userId is null and no active user + * @deprecated Interacting with the master key directly is prohibited. Use a high level function from MasterPasswordService instead. * @param password The user's master password that will be used to derive a master key if one isn't found * @param userId The desired user */ abstract getOrDeriveMasterKey(password: string, userId?: string): Promise; /** * Generates a master key from the provided password - * @deprecated + * @deprecated Interacting with the master key directly is prohibited. * @param password The user's master password * @param email The user's email * @param KdfConfig The user's key derivation function configuration @@ -185,7 +189,7 @@ export abstract class KeyService { /** * Encrypts the existing (or provided) user key with the * provided master key - * @deprecated + * @deprecated Interacting with the master key directly is prohibited. Use a high level function from MasterPasswordService instead. * @param masterKey The user's master key * @param userKey The user key * @returns The user key and the master key protected version of it @@ -198,7 +202,7 @@ export abstract class KeyService { * Creates a master password hash from the user's master password. Can * be used for local authentication or for server authentication depending * on the hashPurpose provided. - * @deprecated + * @deprecated Interacting with the master key directly is prohibited. Use a high level function from MasterPasswordService instead. * @throws Error when password is null or key is null and no active user or active user have no master key * @param password The user's master password * @param key The user's master key or active's user master key. @@ -212,7 +216,7 @@ export abstract class KeyService { ): Promise; /** * Compares the provided master password to the stored password hash. - * @deprecated + * @deprecated Interacting with the master key directly is prohibited. Use a high level function from MasterPasswordService instead. * @param masterPassword The user's master password * @param key The user's master key * @param userId The id of the user to do the operation for. diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index dc7b90ce177..6f0da56e8ad 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -215,9 +215,6 @@ export class DefaultKeyService implements KeyServiceAbstraction { return (await firstValueFrom(this.stateProvider.getUserState$(USER_KEY, userId))) != null; } - /** - * @deprecated Please use `makeMasterPasswordUnlockData` in {@link MasterPasswordService} instead. - */ async makeUserKey(masterKey: MasterKey | null): Promise<[UserKey, EncString]> { if (masterKey == null) { const userId = await firstValueFrom(this.stateProvider.activeUserId$);