Add AuthDiskSource helper for knowing when the user changes (#1007)

This commit is contained in:
David Perez 2024-02-13 12:18:23 -06:00 committed by Álison Fernandes
parent 2739b9e001
commit 6bfb9440b5
4 changed files with 109 additions and 13 deletions

View file

@ -0,0 +1,9 @@
package com.x8bit.bitwarden.data.auth.repository.model
/**
* Contains the values of the previous and new active user IDs when switching active users.
*/
data class UserSwitchingData(
val previousActiveUserId: String?,
val currentActiveUserId: String?,
)

View file

@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository.util
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
import com.x8bit.bitwarden.data.auth.repository.model.UserSwitchingData
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@ -53,3 +54,23 @@ val AuthDiskSource.userOrganizationsListFlow: Flow<List<UserOrganizations>>
) { values -> values.toList() }
}
.distinctUntilChanged()
/**
* Returns a [Flow] that emits every time the active user is changed.
*/
val AuthDiskSource.userSwitchingChangesFlow: Flow<UserSwitchingData>
get() {
var lastActiveUserId: String? = null
return this
.userStateFlow
.map { it?.activeUserId }
.distinctUntilChanged()
.map { activeUserId ->
val previousActiveUserId = lastActiveUserId
lastActiveUserId = activeUserId
UserSwitchingData(
previousActiveUserId = previousActiveUserId,
currentActiveUserId = activeUserId,
)
}
}

View file

@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams
import com.x8bit.bitwarden.data.auth.repository.util.userSwitchingChangesFlow
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
@ -36,7 +37,6 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
@ -300,21 +300,15 @@ class VaultLockManagerImpl(
}
private fun observeUserSwitchingChanges() {
var lastActiveUserId: String? = null
authDiskSource
.userStateFlow
.mapNotNull { it?.activeUserId }
.distinctUntilChanged()
.onEach { activeUserId ->
val previousActiveUserId = lastActiveUserId
lastActiveUserId = activeUserId
if (previousActiveUserId != null &&
activeUserId != previousActiveUserId
) {
.userSwitchingChangesFlow
.onEach { userSwitchingData ->
val previousActiveUserId = userSwitchingData.previousActiveUserId
val currentActiveUserId = userSwitchingData.currentActiveUserId
if (previousActiveUserId != null && currentActiveUserId != null) {
handleUserSwitch(
previousActiveUserId = previousActiveUserId,
currentActiveUserId = activeUserId,
currentActiveUserId = currentActiveUserId,
)
}
}

View file

@ -7,6 +7,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource
import com.x8bit.bitwarden.data.auth.repository.model.Organization
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
import com.x8bit.bitwarden.data.auth.repository.model.UserSwitchingData
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
import io.mockk.every
import io.mockk.mockk
@ -154,4 +155,75 @@ class AuthDiskSourceExtensionsTest {
)
}
}
@Test
fun `userSwitchingChangesFlow should emit changes when active user changes`() = runTest {
authDiskSource.userSwitchingChangesFlow.test {
assertEquals(
UserSwitchingData(
previousActiveUserId = null,
currentActiveUserId = null,
),
awaitItem(),
)
authDiskSource.userState = MOCK_USER_STATE
assertEquals(
UserSwitchingData(
previousActiveUserId = null,
currentActiveUserId = MOCK_USER_ID,
),
awaitItem(),
)
authDiskSource.userState = MOCK_USER_STATE.copy(
accounts = mapOf(
MOCK_USER_ID to MOCK_ACCOUNT,
"mockId-2" to mockk(),
),
)
expectNoEvents()
authDiskSource.userState = null
assertEquals(
UserSwitchingData(
previousActiveUserId = MOCK_USER_ID,
currentActiveUserId = null,
),
awaitItem(),
)
}
}
}
private const val MOCK_USER_ID: String = "mockId-1"
private val MOCK_PROFILE = AccountJson.Profile(
userId = MOCK_USER_ID,
email = "email",
isEmailVerified = true,
name = null,
stamp = null,
organizationId = null,
avatarColorHex = null,
hasPremium = false,
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 = MOCK_USER_ID,
accounts = mapOf(MOCK_USER_ID to MOCK_ACCOUNT),
)