1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PM-23243] In sync response and identity success response add MasterPasswordUnlockDataResponse in decryption options response model. (#15916)

* added master password unlock and decryption option fields into identity token connect response

* incorrect master password unlock response parsing

* use sdk

* use sdk

* better type checking on response parsing

* not using sdk

* revert of bad merge conflicts

* revert of bad merge conflicts

* master password unlock setter in state

* unit test coverage for responses processing

* master password unlock in identity user decryption options

* unit test coverage

* unit test coverage

* unit test coverage

* unit test coverage

* lint error

* set master password unlock data in state on identity response and sync response

* revert change in auth's user decryption options

* remove unnecessary cast

* better docs

* change to relative imports

* MasterPasswordUnlockData serialization issue

* explicit undefined type for `syncUserDecryption`

* incorrect identity token response tests
This commit is contained in:
Maciej Zieniuk
2025-09-05 16:13:56 +02:00
committed by GitHub
parent 6c5e15eb28
commit 203a24723b
24 changed files with 852 additions and 37 deletions

View File

@@ -20,6 +20,11 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service";
import {
MasterKeyWrappedUserKey,
MasterPasswordSalt,
MasterPasswordUnlockData,
} from "@bitwarden/common/key-management/master-password/types/master-password.types";
import {
VaultTimeoutAction,
VaultTimeoutSettingsService,
@@ -33,7 +38,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
import { FakeAccountService, makeEncString, mockAccountServiceWith } from "@bitwarden/common/spec";
import {
PasswordStrengthServiceAbstraction,
PasswordStrengthService,
@@ -41,7 +46,7 @@ import {
import { CsprngArray } from "@bitwarden/common/types/csprng";
import { UserId } from "@bitwarden/common/types/guid";
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management";
import { LoginStrategyServiceAbstraction } from "../abstractions";
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
@@ -56,7 +61,7 @@ const masterPassword = "password";
const deviceId = Utils.newGuid();
const accessToken = "ACCESS_TOKEN";
const refreshToken = "REFRESH_TOKEN";
const userKey = "USER_KEY";
const encryptedUserKey = makeEncString("USER_KEY");
const privateKey = "PRIVATE_KEY";
const kdf = 0;
const kdfIterations = 10000;
@@ -65,6 +70,14 @@ const masterPasswordHash = "MASTER_PASSWORD_HASH";
const name = "NAME";
const defaultUserDecryptionOptionsServerResponse: IUserDecryptionOptionsServerResponse = {
HasMasterPassword: true,
MasterPasswordUnlock: {
Salt: email,
Kdf: {
KdfType: kdf,
Iterations: kdfIterations,
},
MasterKeyEncryptedUserKey: encryptedUserKey.encryptedString,
},
};
const decodedToken = {
@@ -86,7 +99,7 @@ export function identityTokenResponseFactory(
ForcePasswordReset: false,
Kdf: kdf,
KdfIterations: kdfIterations,
Key: userKey,
Key: encryptedUserKey.encryptedString,
PrivateKey: privateKey,
ResetMasterPassword: false,
access_token: accessToken,
@@ -247,6 +260,14 @@ describe("LoginStrategy", () => {
expect(userDecryptionOptionsService.setUserDecryptionOptions).toHaveBeenCalledWith(
UserDecryptionOptions.fromResponse(idTokenResponse),
);
expect(masterPasswordService.mock.setMasterPasswordUnlockData).toHaveBeenCalledWith(
new MasterPasswordUnlockData(
email as MasterPasswordSalt,
new PBKDF2KdfConfig(kdfIterations),
encryptedUserKey as MasterKeyWrappedUserKey,
),
userId,
);
expect(messagingService.send).toHaveBeenCalledWith("loggedIn");
});

View File

@@ -199,6 +199,15 @@ export abstract class LoginStrategy {
UserDecryptionOptions.fromResponse(tokenResponse),
);
if (tokenResponse.userDecryptionOptions?.masterPasswordUnlock != null) {
const masterPasswordUnlockData =
tokenResponse.userDecryptionOptions.masterPasswordUnlock.toMasterPasswordUnlockData();
await this.masterPasswordService.setMasterPasswordUnlockData(
masterPasswordUnlockData,
userId,
);
}
const vaultTimeoutAction = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(userId),
);

View File

@@ -2,11 +2,9 @@
// @ts-strict-ignore
import { Jsonify } from "type-fest";
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
import { KeyConnectorUserDecryptionOptionResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/key-connector-user-decryption-option.response";
import { TrustedDeviceUserDecryptionOptionResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/trusted-device-user-decryption-option.response";
// FIXME: remove `src` and fix import
// eslint-disable-next-line no-restricted-imports
import { IdentityTokenResponse } from "@bitwarden/common/src/auth/models/response/identity-token.response";
/**
* Key Connector decryption options. Intended to be sent to the client for use after authentication.