@@ -30,6 +30,7 @@ import com.bitwarden.network.model.GetTokenResponseJson
3030import com.bitwarden.network.model.IdentityTokenAuthModel
3131import com.bitwarden.network.model.KdfTypeJson
3232import com.bitwarden.network.model.KeyConnectorMasterKeyResponseJson
33+ import com.bitwarden.network.model.MasterPasswordUnlockDataJson
3334import com.bitwarden.network.model.OrganizationAutoEnrollStatusResponseJson
3435import com.bitwarden.network.model.OrganizationKeysResponseJson
3536import com.bitwarden.network.model.OrganizationType
@@ -76,6 +77,7 @@ import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL
7677import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL_2
7778import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL_3
7879import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL_4
80+ import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toKdfRequestModel
7981import com.x8bit.bitwarden.data.auth.manager.AuthRequestManager
8082import com.x8bit.bitwarden.data.auth.manager.KdfManager
8183import com.x8bit.bitwarden.data.auth.manager.KeyConnectorManager
@@ -6985,6 +6987,79 @@ class AuthRepositoryTest {
69856987 )
69866988 }
69876989
6990+ @Test
6991+ fun `unlockVault uses user decryption options for KDF when init method is password` () =
6992+ runTest {
6993+ val successResponse = GET_TOKEN_WITH_ACCOUNT_KEYS_RESPONSE_SUCCESS
6994+ coEvery {
6995+ identityService.preLogin(email = EMAIL )
6996+ } returns PRE_LOGIN_SUCCESS .asSuccess()
6997+ coEvery {
6998+ identityService.getToken(
6999+ email = EMAIL ,
7000+ authModel = IdentityTokenAuthModel .MasterPassword (
7001+ username = EMAIL ,
7002+ password = PASSWORD_HASH ,
7003+ ),
7004+ uniqueAppId = UNIQUE_APP_ID ,
7005+ )
7006+ } returns successResponse.asSuccess()
7007+ coEvery {
7008+ vaultRepository.unlockVault(
7009+ userId = USER_ID_1 ,
7010+ email = EMAIL ,
7011+ kdf = ACCOUNT_2 .profile.toSdkParams(),
7012+ privateKey = successResponse.accountKeys!!
7013+ .publicKeyEncryptionKeyPair
7014+ .wrappedPrivateKey,
7015+ signingKey = successResponse.accountKeys
7016+ ?.signatureKeyPair
7017+ ?.wrappedSigningKey,
7018+ securityState = successResponse.accountKeys
7019+ ?.securityState
7020+ ?.securityState,
7021+ initUserCryptoMethod = InitUserCryptoMethod .Password (
7022+ password = PASSWORD ,
7023+ userKey = successResponse.key!! ,
7024+ ),
7025+ organizationKeys = null ,
7026+ )
7027+ } returns VaultUnlockResult .Success
7028+ coEvery { vaultRepository.syncIfNecessary() } just runs
7029+ every {
7030+ GET_TOKEN_WITH_ACCOUNT_KEYS_RESPONSE_SUCCESS .toUserState(
7031+ previousUserState = null ,
7032+ environmentUrlData = EnvironmentUrlDataJson .DEFAULT_US ,
7033+ )
7034+ } returns SINGLE_USER_STATE_1_WITH_DECRYPTION_OPTIONS
7035+
7036+ repository.login(email = EMAIL , password = PASSWORD )
7037+
7038+ coVerify {
7039+ vaultRepository.unlockVault(
7040+ userId = USER_ID_1 ,
7041+ email = EMAIL ,
7042+ kdf = ACCOUNT_2 .profile.toSdkParams(),
7043+ privateKey = successResponse.accountKeys!!
7044+ .publicKeyEncryptionKeyPair
7045+ .wrappedPrivateKey,
7046+ signingKey = successResponse.accountKeys
7047+ ?.signatureKeyPair
7048+ ?.wrappedSigningKey,
7049+ securityState = successResponse.accountKeys
7050+ ?.securityState
7051+ ?.securityState,
7052+ initUserCryptoMethod = InitUserCryptoMethod .Password (
7053+ password = PASSWORD ,
7054+ userKey = successResponse.key!! ,
7055+ ),
7056+ organizationKeys = null ,
7057+ )
7058+ vaultRepository.syncIfNecessary()
7059+ settingsRepository.storeUserHasLoggedInValue(userId = USER_ID_1 )
7060+ }
7061+ }
7062+
69887063 companion object {
69897064 private val FIXED_CLOCK : Clock = Clock .fixed(
69907065 Instant .parse(" 2023-10-27T12:00:00Z" ),
@@ -7175,6 +7250,28 @@ class AuthRepositoryTest {
71757250 ),
71767251 )
71777252
7253+ private val MOCK_MASTER_PASSWORD_UNLOCK_DATA = MasterPasswordUnlockDataJson (
7254+ salt = " mockSalt" ,
7255+ kdf = ACCOUNT_2 .profile.toSdkParams().toKdfRequestModel(),
7256+ masterKeyWrappedUserKey = " masterKeyWrappedUserKeyMock" ,
7257+ )
7258+
7259+ private val SINGLE_USER_STATE_1_WITH_DECRYPTION_OPTIONS = UserStateJson (
7260+ activeUserId = USER_ID_1 ,
7261+ accounts = mapOf (
7262+ USER_ID_1 to ACCOUNT_1 .copy(
7263+ profile = ACCOUNT_1 .profile.copy(
7264+ userDecryptionOptions = UserDecryptionOptionsJson (
7265+ hasMasterPassword = true ,
7266+ keyConnectorUserDecryptionOptions = null ,
7267+ trustedDeviceUserDecryptionOptions = null ,
7268+ masterPasswordUnlock = MOCK_MASTER_PASSWORD_UNLOCK_DATA ,
7269+ ),
7270+ ),
7271+ ),
7272+ ),
7273+ )
7274+
71787275 private val SINGLE_USER_STATE_2 = UserStateJson (
71797276 activeUserId = USER_ID_2 ,
71807277 accounts = mapOf (
0 commit comments