mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
[PM-8933] Require userId on setUserKey (#9675)
* Updated all sets of user key to pass in userId * Added userId on auth request login. * Fixed tests. * Fixed tests to pass in UserId * Added parameter to tests. * Addressed PR feedback. * Merged main
This commit is contained in:
@@ -49,19 +49,23 @@ export abstract class AuthRequestServiceAbstraction {
|
||||
* Sets the `UserKey` from an auth request. Auth request must have a `UserKey`.
|
||||
* @param authReqResponse The auth request.
|
||||
* @param authReqPrivateKey The private key corresponding to the public key sent in the auth request.
|
||||
* @param userId The ID of the user for whose account we will set the key.
|
||||
*/
|
||||
abstract setUserKeyAfterDecryptingSharedUserKey: (
|
||||
authReqResponse: AuthRequestResponse,
|
||||
authReqPrivateKey: ArrayBuffer,
|
||||
userId: UserId,
|
||||
) => Promise<void>;
|
||||
/**
|
||||
* Sets the `MasterKey` and `MasterKeyHash` from an auth request. Auth request must have a `MasterKey` and `MasterKeyHash`.
|
||||
* @param authReqResponse The auth request.
|
||||
* @param authReqPrivateKey The private key corresponding to the public key sent in the auth request.
|
||||
* @param userId The ID of the user for whose account we will set the keys.
|
||||
*/
|
||||
abstract setKeysAfterDecryptingSharedMasterKeyAndHash: (
|
||||
authReqResponse: AuthRequestResponse,
|
||||
authReqPrivateKey: ArrayBuffer,
|
||||
userId: UserId,
|
||||
) => Promise<void>;
|
||||
/**
|
||||
* Decrypts a `UserKey` from a public key encrypted `UserKey`.
|
||||
|
||||
@@ -159,7 +159,7 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
mockUserId,
|
||||
);
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey, mockUserId);
|
||||
expect(deviceTrustService.trustDeviceIfRequired).toHaveBeenCalled();
|
||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, mockUserId);
|
||||
});
|
||||
@@ -184,7 +184,7 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
|
||||
// setMasterKeyEncryptedUserKey, setUserKey, and setPrivateKey should still be called
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(decUserKey);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(decUserKey, mockUserId);
|
||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, mockUserId);
|
||||
|
||||
// trustDeviceIfRequired should be called
|
||||
|
||||
@@ -102,7 +102,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
||||
|
||||
if (authRequestCredentials.decryptedUserKey) {
|
||||
await this.cryptoService.setUserKey(authRequestCredentials.decryptedUserKey);
|
||||
await this.cryptoService.setUserKey(authRequestCredentials.decryptedUserKey, userId);
|
||||
} else {
|
||||
await this.trySetUserKeyWithMasterKey(userId);
|
||||
|
||||
@@ -115,7 +115,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
||||
if (masterKey) {
|
||||
const userKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(masterKey);
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
await this.cryptoService.setUserKey(userKey, userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ describe("SsoLoginStrategy", () => {
|
||||
expect(deviceTrustService.getDeviceKey).toHaveBeenCalledTimes(1);
|
||||
expect(deviceTrustService.decryptUserKeyWithDeviceKey).toHaveBeenCalledTimes(1);
|
||||
expect(cryptoSvcSetUserKeySpy).toHaveBeenCalledTimes(1);
|
||||
expect(cryptoSvcSetUserKeySpy).toHaveBeenCalledWith(mockUserKey);
|
||||
expect(cryptoSvcSetUserKeySpy).toHaveBeenCalledWith(mockUserKey, userId);
|
||||
});
|
||||
|
||||
it("does not set the user key when deviceKey is missing", async () => {
|
||||
@@ -498,7 +498,7 @@ describe("SsoLoginStrategy", () => {
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey, userId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -554,7 +554,7 @@ describe("SsoLoginStrategy", () => {
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey, userId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -255,6 +255,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
await this.authRequestService.setKeysAfterDecryptingSharedMasterKeyAndHash(
|
||||
adminAuthReqResponse,
|
||||
adminAuthReqStorable.privateKey,
|
||||
userId,
|
||||
);
|
||||
} else {
|
||||
// if masterPasswordHash is null, we will always receive authReqResponse.key
|
||||
@@ -262,6 +263,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
await this.authRequestService.setUserKeyAfterDecryptingSharedUserKey(
|
||||
adminAuthReqResponse,
|
||||
adminAuthReqStorable.privateKey,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -321,7 +323,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
);
|
||||
|
||||
if (userKey) {
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
await this.cryptoService.setUserKey(userKey, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +339,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
}
|
||||
|
||||
const userKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(masterKey);
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
await this.cryptoService.setUserKey(userKey, userId);
|
||||
}
|
||||
|
||||
protected override async setPrivateKey(
|
||||
|
||||
@@ -133,14 +133,18 @@ describe("AuthRequestService", () => {
|
||||
cryptoService.setUserKey.mockResolvedValueOnce(undefined);
|
||||
|
||||
// Act
|
||||
await sut.setUserKeyAfterDecryptingSharedUserKey(mockAuthReqResponse, mockPrivateKey);
|
||||
await sut.setUserKeyAfterDecryptingSharedUserKey(
|
||||
mockAuthReqResponse,
|
||||
mockPrivateKey,
|
||||
mockUserId,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(sut.decryptPubKeyEncryptedUserKey).toBeCalledWith(
|
||||
mockAuthReqResponse.key,
|
||||
mockPrivateKey,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toBeCalledWith(mockDecryptedUserKey);
|
||||
expect(cryptoService.setUserKey).toBeCalledWith(mockDecryptedUserKey, mockUserId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -169,7 +173,11 @@ describe("AuthRequestService", () => {
|
||||
cryptoService.setUserKey.mockResolvedValueOnce(undefined);
|
||||
|
||||
// Act
|
||||
await sut.setKeysAfterDecryptingSharedMasterKeyAndHash(mockAuthReqResponse, mockPrivateKey);
|
||||
await sut.setKeysAfterDecryptingSharedMasterKeyAndHash(
|
||||
mockAuthReqResponse,
|
||||
mockPrivateKey,
|
||||
mockUserId,
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(sut.decryptPubKeyEncryptedMasterKeyAndHash).toBeCalledWith(
|
||||
@@ -190,7 +198,7 @@ describe("AuthRequestService", () => {
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(mockDecryptedUserKey);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(mockDecryptedUserKey, mockUserId);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -126,17 +126,19 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
||||
async setUserKeyAfterDecryptingSharedUserKey(
|
||||
authReqResponse: AuthRequestResponse,
|
||||
authReqPrivateKey: Uint8Array,
|
||||
userId: UserId,
|
||||
) {
|
||||
const userKey = await this.decryptPubKeyEncryptedUserKey(
|
||||
authReqResponse.key,
|
||||
authReqPrivateKey,
|
||||
);
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
await this.cryptoService.setUserKey(userKey, userId);
|
||||
}
|
||||
|
||||
async setKeysAfterDecryptingSharedMasterKeyAndHash(
|
||||
authReqResponse: AuthRequestResponse,
|
||||
authReqPrivateKey: Uint8Array,
|
||||
userId: UserId,
|
||||
) {
|
||||
const { masterKey, masterKeyHash } = await this.decryptPubKeyEncryptedMasterKeyAndHash(
|
||||
authReqResponse.key,
|
||||
@@ -148,11 +150,10 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
||||
const userKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(masterKey);
|
||||
|
||||
// Set masterKey + masterKeyHash in state after decryption (in case decryption fails)
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
||||
await this.masterPasswordService.setMasterKeyHash(masterKeyHash, userId);
|
||||
|
||||
await this.cryptoService.setUserKey(userKey);
|
||||
await this.cryptoService.setUserKey(userKey, userId);
|
||||
}
|
||||
|
||||
// Decryption helpers
|
||||
|
||||
Reference in New Issue
Block a user