Skip to content

Commit a7d3c0f

Browse files
[PM-23809] Add simplified interface to MP service (#15631)
* Add new mp service api * Fix tests * Add test coverage * Add newline * Fix type * Rename to "unwrapUserKeyFromMasterPasswordUnlockData" * Fix build * Fix build on cli * Fix linting * Re-sort spec * Add tests * Fix test and build issues * Fix build * Clean up * Remove introduced function * Clean up comments * Fix abstract class types * Fix comments * Cleanup * Cleanup * Update libs/common/src/key-management/master-password/types/master-password.types.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/services/master-password.service.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/types/master-password.types.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Add comments * Fix build * Add arg null check * Cleanup * Fix build * Fix build on browser * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Add tests for null params * Cleanup and deprecate more functions * Fix formatting * Prettier * Clean up * Update libs/key-management/src/abstractions/key.service.ts Co-authored-by: Thomas Avery <[email protected]> * Make emailToSalt private and expose abstract saltForUser * Add tests * Add docs * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Thomas Avery <[email protected]> --------- Co-authored-by: Thomas Avery <[email protected]>
1 parent 95f0373 commit a7d3c0f

File tree

11 files changed

+418
-6
lines changed

11 files changed

+418
-6
lines changed

apps/browser/src/background/main.background.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,8 @@ export default class MainBackground {
668668
this.keyGenerationService,
669669
this.encryptService,
670670
this.logService,
671+
this.cryptoFunctionService,
672+
this.accountService,
671673
);
672674

673675
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);

apps/cli/src/service-container/service-container.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,16 +431,17 @@ export class ServiceContainer {
431431
migrationRunner,
432432
);
433433

434+
this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider);
434435
this.masterPasswordService = new MasterPasswordService(
435436
this.stateProvider,
436437
this.stateService,
437438
this.keyGenerationService,
438439
this.encryptService,
439440
this.logService,
441+
this.cryptoFunctionService,
442+
this.accountService,
440443
);
441444

442-
this.kdfConfigService = new DefaultKdfConfigService(this.stateProvider);
443-
444445
this.pinService = new PinService(
445446
this.accountService,
446447
this.cryptoFunctionService,

libs/angular/src/services/jslib-services.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,8 @@ const safeProviders: SafeProvider[] = [
10211021
KeyGenerationServiceAbstraction,
10221022
EncryptService,
10231023
LogService,
1024+
CryptoFunctionServiceAbstraction,
1025+
AccountServiceAbstraction,
10241026
],
10251027
}),
10261028
safeProvider({

libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import { Observable } from "rxjs";
22

3+
// eslint-disable-next-line no-restricted-imports
4+
import { KdfConfig } from "@bitwarden/key-management";
5+
36
import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason";
47
import { UserId } from "../../../types/guid";
58
import { MasterKey, UserKey } from "../../../types/key";
69
import { EncString } from "../../crypto/models/enc-string";
10+
import {
11+
MasterPasswordAuthenticationData,
12+
MasterPasswordSalt,
13+
MasterPasswordUnlockData,
14+
} from "../types/master-password.types";
715

816
export abstract class MasterPasswordServiceAbstraction {
917
/**
@@ -12,14 +20,23 @@ export abstract class MasterPasswordServiceAbstraction {
1220
* @throws If the user ID is missing.
1321
*/
1422
abstract forceSetPasswordReason$: (userId: UserId) => Observable<ForceSetPasswordReason>;
23+
/**
24+
* An observable that emits the master password salt for the user.
25+
* @param userId The user ID.
26+
* @throws If the user ID is missing.
27+
* @throws If the user ID is provided, but the user is not found.
28+
*/
29+
abstract saltForUser$: (userId: UserId) => Observable<MasterPasswordSalt>;
1530
/**
1631
* An observable that emits the master key for the user.
32+
* @deprecated Interacting with the master-key directly is deprecated. Please use {@link makeMasterPasswordUnlockData}, {@link makeMasterPasswordAuthenticationData} or {@link unwrapUserKeyFromMasterPasswordUnlockData} instead.
1733
* @param userId The user ID.
1834
* @throws If the user ID is missing.
1935
*/
2036
abstract masterKey$: (userId: UserId) => Observable<MasterKey>;
2137
/**
2238
* An observable that emits the master key hash for the user.
39+
* @deprecated Interacting with the master-key directly is deprecated. Please use {@link makeMasterPasswordAuthenticationData}.
2340
* @param userId The user ID.
2441
* @throws If the user ID is missing.
2542
*/
@@ -32,6 +49,7 @@ export abstract class MasterPasswordServiceAbstraction {
3249
abstract getMasterKeyEncryptedUserKey: (userId: UserId) => Promise<EncString>;
3350
/**
3451
* Decrypts the user key with the provided master key
52+
* @deprecated Interacting with the master-key directly is deprecated. Please use {@link unwrapUserKeyFromMasterPasswordUnlockData} instead.
3553
* @param masterKey The user's master key
3654
* * @param userId The desired user
3755
* @param userKey The user's encrypted symmetric key
@@ -44,33 +62,76 @@ export abstract class MasterPasswordServiceAbstraction {
4462
userId: string,
4563
userKey?: EncString,
4664
) => Promise<UserKey | null>;
65+
66+
/**
67+
* Makes the authentication hash for authenticating to the server with the master password.
68+
* @param password The master password.
69+
* @param kdf The KDF configuration.
70+
* @param salt The master password salt to use. See {@link saltForUser$} for current salt.
71+
* @throws If password, KDF or salt are null or undefined.
72+
*/
73+
abstract makeMasterPasswordAuthenticationData: (
74+
password: string,
75+
kdf: KdfConfig,
76+
salt: MasterPasswordSalt,
77+
) => Promise<MasterPasswordAuthenticationData>;
78+
79+
/**
80+
* Creates a MasterPasswordUnlockData bundle that encrypts the user-key with a key derived from the password. The
81+
* bundle also contains the KDF settings and salt used to derive the key, which are required to decrypt the user-key later.
82+
* @param password The master password.
83+
* @param kdf The KDF configuration.
84+
* @param salt The master password salt to use. See {@link saltForUser$} for current salt.
85+
* @param userKey The user's userKey to encrypt.
86+
* @throws If password, KDF, salt, or userKey are null or undefined.
87+
*/
88+
abstract makeMasterPasswordUnlockData: (
89+
password: string,
90+
kdf: KdfConfig,
91+
salt: MasterPasswordSalt,
92+
userKey: UserKey,
93+
) => Promise<MasterPasswordUnlockData>;
94+
95+
/**
96+
* Unwraps a user-key that was wrapped with a password provided KDF settings. The same KDF settings and salt must be provided to unwrap the user-key, otherwise it will fail to decrypt.
97+
* @throws If the encryption type is not supported.
98+
* @throws If the password, KDF, or salt don't match the original wrapping parameters.
99+
*/
100+
abstract unwrapUserKeyFromMasterPasswordUnlockData: (
101+
password: string,
102+
masterPasswordUnlockData: MasterPasswordUnlockData,
103+
) => Promise<UserKey>;
47104
}
48105

49106
export abstract class InternalMasterPasswordServiceAbstraction extends MasterPasswordServiceAbstraction {
50107
/**
51108
* Set the master key for the user.
52109
* Note: Use {@link clearMasterKey} to clear the master key.
110+
* @deprecated Interacting with the master-key directly is deprecated.
53111
* @param masterKey The master key.
54112
* @param userId The user ID.
55113
* @throws If the user ID or master key is missing.
56114
*/
57115
abstract setMasterKey: (masterKey: MasterKey, userId: UserId) => Promise<void>;
58116
/**
59117
* Clear the master key for the user.
118+
* @deprecated Interacting with the master-key directly is deprecated.
60119
* @param userId The user ID.
61120
* @throws If the user ID is missing.
62121
*/
63122
abstract clearMasterKey: (userId: UserId) => Promise<void>;
64123
/**
65124
* Set the master key hash for the user.
66125
* Note: Use {@link clearMasterKeyHash} to clear the master key hash.
126+
* @deprecated Interacting with the master-key directly is deprecated.
67127
* @param masterKeyHash The master key hash.
68128
* @param userId The user ID.
69129
* @throws If the user ID or master key hash is missing.
70130
*/
71131
abstract setMasterKeyHash: (masterKeyHash: string, userId: UserId) => Promise<void>;
72132
/**
73133
* Clear the master key hash for the user.
134+
* @deprecated Interacting with the master-key directly is deprecated.
74135
* @param userId The user ID.
75136
* @throws If the user ID is missing.
76137
*/

libs/common/src/key-management/master-password/services/fake-master-password.service.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,20 @@
33
import { mock } from "jest-mock-extended";
44
import { ReplaySubject, Observable } from "rxjs";
55

6+
// FIXME: Update this file to be type safe and remove this and next line
7+
// eslint-disable-next-line no-restricted-imports
8+
import { KdfConfig } from "@bitwarden/key-management";
9+
610
import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason";
711
import { UserId } from "../../../types/guid";
812
import { MasterKey, UserKey } from "../../../types/key";
913
import { EncString } from "../../crypto/models/enc-string";
1014
import { InternalMasterPasswordServiceAbstraction } from "../abstractions/master-password.service.abstraction";
15+
import {
16+
MasterPasswordAuthenticationData,
17+
MasterPasswordSalt,
18+
MasterPasswordUnlockData,
19+
} from "../types/master-password.types";
1120

1221
export class FakeMasterPasswordService implements InternalMasterPasswordServiceAbstraction {
1322
mock = mock<InternalMasterPasswordServiceAbstraction>();
@@ -24,6 +33,10 @@ export class FakeMasterPasswordService implements InternalMasterPasswordServiceA
2433
this.masterKeyHashSubject.next(initialMasterKeyHash);
2534
}
2635

36+
saltForUser$(userId: UserId): Observable<MasterPasswordSalt> {
37+
return this.mock.saltForUser$(userId);
38+
}
39+
2740
masterKey$(userId: UserId): Observable<MasterKey> {
2841
return this.masterKeySubject.asObservable();
2942
}
@@ -71,4 +84,28 @@ export class FakeMasterPasswordService implements InternalMasterPasswordServiceA
7184
): Promise<UserKey> {
7285
return this.mock.decryptUserKeyWithMasterKey(masterKey, userId, userKey);
7386
}
87+
88+
makeMasterPasswordAuthenticationData(
89+
password: string,
90+
kdf: KdfConfig,
91+
salt: MasterPasswordSalt,
92+
): Promise<MasterPasswordAuthenticationData> {
93+
return this.mock.makeMasterPasswordAuthenticationData(password, kdf, salt);
94+
}
95+
96+
makeMasterPasswordUnlockData(
97+
password: string,
98+
kdf: KdfConfig,
99+
salt: MasterPasswordSalt,
100+
userKey: UserKey,
101+
): Promise<MasterPasswordUnlockData> {
102+
return this.mock.makeMasterPasswordUnlockData(password, kdf, salt, userKey);
103+
}
104+
105+
unwrapUserKeyFromMasterPasswordUnlockData(
106+
password: string,
107+
masterPasswordUnlockData: MasterPasswordUnlockData,
108+
): Promise<UserKey> {
109+
return this.mock.unwrapUserKeyFromMasterPasswordUnlockData(password, masterPasswordUnlockData);
110+
}
74111
}

0 commit comments

Comments
 (0)