mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Update UserStateJson with avatarColor and securityStamp from sync (#265)
This commit is contained in:
parent
58eb4d4107
commit
feba8595b3
5 changed files with 195 additions and 44 deletions
|
@ -0,0 +1,33 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.util
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
|
||||
/**
|
||||
* Updates the given [UserStateJson] with the data from the [syncResponse] to return a new
|
||||
* [UserStateJson]. The original will be returned if the sync response does not match any accounts
|
||||
* in the [UserStateJson].
|
||||
*/
|
||||
@Suppress("ReturnCount")
|
||||
fun UserStateJson.toUpdatedUserStateJson(
|
||||
syncResponse: SyncResponseJson,
|
||||
): UserStateJson {
|
||||
val userId = syncResponse.profile?.id ?: return this
|
||||
val account = this.accounts[userId] ?: return this
|
||||
val profile = account.profile
|
||||
// TODO: Update additional missing UserStateJson properties (BIT-916)
|
||||
val updatedProfile = profile
|
||||
.copy(
|
||||
avatarColorHex = syncResponse.profile.avatarColor,
|
||||
stamp = syncResponse.profile.securityStamp,
|
||||
)
|
||||
val updatedAccount = account.copy(profile = updatedProfile)
|
||||
return this
|
||||
.copy(
|
||||
accounts = accounts
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
replace(userId, updatedAccount)
|
||||
},
|
||||
)
|
||||
}
|
|
@ -5,6 +5,7 @@ import com.bitwarden.core.FolderView
|
|||
import com.bitwarden.core.InitCryptoRequest
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.toUpdatedUserStateJson
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.util.isNoConnectionError
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
|
@ -85,6 +86,13 @@ class VaultRepositoryImpl constructor(
|
|||
.sync()
|
||||
.fold(
|
||||
onSuccess = { syncResponse ->
|
||||
// Update user information with additional information from sync response
|
||||
authDiskSource.userState = authDiskSource
|
||||
.userState
|
||||
?.toUpdatedUserStateJson(
|
||||
syncResponse = syncResponse,
|
||||
)
|
||||
|
||||
storeUserKeyAndPrivateKey(
|
||||
userKey = syncResponse.profile?.key,
|
||||
privateKey = syncResponse.profile?.privateKey,
|
||||
|
|
|
@ -41,6 +41,13 @@ class FakeAuthDiskSource : AuthDiskSource {
|
|||
|
||||
private val storedPrivateKeys = mutableMapOf<String, String?>()
|
||||
|
||||
/**
|
||||
* Assert that the given [userState] matches the currently tracked value.
|
||||
*/
|
||||
fun assertUserState(userState: UserStateJson) {
|
||||
assertEquals(userState, this.userState)
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the [userKey] was stored successfully using the [userId].
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package com.x8bit.bitwarden.data.auth.repository.util
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class UserStateJsonExtensionsTest {
|
||||
@Test
|
||||
fun `toUpdatedUserStateJson should do nothing for a non-matching account`() {
|
||||
val originalUserState = UserStateJson(
|
||||
activeUserId = "activeUserId",
|
||||
accounts = mapOf(
|
||||
"activeUserId" to mockk(),
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
originalUserState,
|
||||
originalUserState
|
||||
.toUpdatedUserStateJson(
|
||||
syncResponse = mockk {
|
||||
every { profile } returns mockk {
|
||||
every { id } returns "otherUserId"
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toUpdatedUserStateJson should update the correct account with new information`() {
|
||||
val originalProfile = AccountJson.Profile(
|
||||
userId = "activeUserId",
|
||||
email = "email",
|
||||
isEmailVerified = true,
|
||||
name = "name",
|
||||
stamp = null,
|
||||
organizationId = null,
|
||||
avatarColorHex = null,
|
||||
hasPremium = true,
|
||||
forcePasswordResetReason = null,
|
||||
kdfType = KdfTypeJson.ARGON2_ID,
|
||||
kdfIterations = 600000,
|
||||
kdfMemory = 16,
|
||||
kdfParallelism = 4,
|
||||
userDecryptionOptions = null,
|
||||
)
|
||||
val originalAccount = AccountJson(
|
||||
profile = originalProfile,
|
||||
tokens = mockk(),
|
||||
settings = mockk(),
|
||||
)
|
||||
assertEquals(
|
||||
UserStateJson(
|
||||
activeUserId = "activeUserId",
|
||||
accounts = mapOf(
|
||||
"activeUserId" to originalAccount.copy(
|
||||
profile = originalProfile.copy(
|
||||
avatarColorHex = "avatarColor",
|
||||
stamp = "securityStamp",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
UserStateJson(
|
||||
activeUserId = "activeUserId",
|
||||
accounts = mapOf(
|
||||
"activeUserId" to originalAccount,
|
||||
),
|
||||
)
|
||||
.toUpdatedUserStateJson(
|
||||
syncResponse = mockk {
|
||||
every { profile } returns mockk {
|
||||
every { id } returns "activeUserId"
|
||||
every { avatarColor } returns "avatarColor"
|
||||
every { securityStamp } returns "securityStamp"
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -74,12 +74,26 @@ class VaultRepositoryTest {
|
|||
|
||||
vaultRepository.sync()
|
||||
|
||||
val updatedUserState = MOCK_USER_STATE
|
||||
.copy(
|
||||
accounts = mapOf(
|
||||
"mockId-1" to MOCK_ACCOUNT.copy(
|
||||
profile = MOCK_PROFILE.copy(
|
||||
avatarColorHex = "mockAvatarColor-1",
|
||||
stamp = "mockSecurityStamp-1",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
fakeAuthDiskSource.assertUserState(
|
||||
userState = updatedUserState,
|
||||
)
|
||||
fakeAuthDiskSource.assertUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.assertPrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
assertEquals(
|
||||
|
@ -462,11 +476,11 @@ class VaultRepositoryTest {
|
|||
vaultSdkSource.decryptSendList(listOf(createMockSdkSend(number = 1)))
|
||||
} returns listOf(createMockSendView(number = 1)).asSuccess()
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -507,11 +521,11 @@ class VaultRepositoryTest {
|
|||
vaultSdkSource.decryptSendList(listOf(createMockSdkSend(number = 1)))
|
||||
} returns listOf(createMockSendView(number = 1)).asSuccess()
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -551,11 +565,11 @@ class VaultRepositoryTest {
|
|||
vaultSdkSource.decryptFolderList(listOf(createMockSdkFolder(1)))
|
||||
} returns listOf(createMockFolderView(number = 1)).asSuccess()
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -598,11 +612,11 @@ class VaultRepositoryTest {
|
|||
vaultSdkSource.decryptFolderList(listOf(createMockSdkFolder(1)))
|
||||
} returns mockk()
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -639,11 +653,11 @@ class VaultRepositoryTest {
|
|||
vaultSdkSource.decryptFolderList(listOf(createMockSdkFolder(1)))
|
||||
} returns mockk()
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -685,11 +699,11 @@ class VaultRepositoryTest {
|
|||
runTest {
|
||||
val result = vaultRepository.unlockVaultAndSync(masterPassword = "")
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = null,
|
||||
)
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = "mockPrivateKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -704,11 +718,11 @@ class VaultRepositoryTest {
|
|||
runTest {
|
||||
val result = vaultRepository.unlockVaultAndSync(masterPassword = "")
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
userKey = "mockKey-1",
|
||||
)
|
||||
fakeAuthDiskSource.storePrivateKey(
|
||||
userId = "mockUserId",
|
||||
userId = "mockId-1",
|
||||
privateKey = null,
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
|
@ -1014,33 +1028,37 @@ class VaultRepositoryTest {
|
|||
}
|
||||
}
|
||||
|
||||
private val MOCK_USER_STATE = UserStateJson(
|
||||
activeUserId = "mockUserId",
|
||||
accounts = mapOf(
|
||||
"mockUserId" to AccountJson(
|
||||
profile = AccountJson.Profile(
|
||||
userId = "activeUserId",
|
||||
email = "email",
|
||||
isEmailVerified = true,
|
||||
name = null,
|
||||
stamp = null,
|
||||
organizationId = null,
|
||||
avatarColorHex = null,
|
||||
hasPremium = true,
|
||||
forcePasswordResetReason = null,
|
||||
kdfType = null,
|
||||
kdfIterations = null,
|
||||
kdfMemory = null,
|
||||
kdfParallelism = null,
|
||||
userDecryptionOptions = null,
|
||||
),
|
||||
tokens = AccountJson.Tokens(
|
||||
accessToken = "accessToken",
|
||||
refreshToken = "refreshToken",
|
||||
),
|
||||
settings = AccountJson.Settings(
|
||||
environmentUrlData = null,
|
||||
),
|
||||
),
|
||||
private val MOCK_PROFILE = AccountJson.Profile(
|
||||
userId = "mockId-1",
|
||||
email = "email",
|
||||
isEmailVerified = true,
|
||||
name = null,
|
||||
stamp = null,
|
||||
organizationId = null,
|
||||
avatarColorHex = null,
|
||||
hasPremium = true,
|
||||
forcePasswordResetReason = null,
|
||||
kdfType = null,
|
||||
kdfIterations = null,
|
||||
kdfMemory = null,
|
||||
kdfParallelism = null,
|
||||
userDecryptionOptions = null,
|
||||
)
|
||||
|
||||
private val MOCK_ACCOUNT = AccountJson(
|
||||
profile = MOCK_PROFILE,
|
||||
tokens = AccountJson.Tokens(
|
||||
accessToken = "accessToken",
|
||||
refreshToken = "refreshToken",
|
||||
),
|
||||
settings = AccountJson.Settings(
|
||||
environmentUrlData = null,
|
||||
),
|
||||
)
|
||||
|
||||
private val MOCK_USER_STATE = UserStateJson(
|
||||
activeUserId = "mockId-1",
|
||||
accounts = mapOf(
|
||||
"mockId-1" to MOCK_ACCOUNT,
|
||||
),
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue