mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 10:48:47 +03:00
Allow for null access tokens for soft logout states (#596)
This commit is contained in:
parent
5288a697e5
commit
8f22231c4a
25 changed files with 281 additions and 19 deletions
|
@ -23,6 +23,10 @@ data class AccountJson(
|
|||
@SerialName("settings")
|
||||
val settings: Settings,
|
||||
) {
|
||||
/**
|
||||
* Whether or not the account should be considered logged in.
|
||||
*/
|
||||
val isLoggedIn: Boolean get() = tokens.accessToken != null
|
||||
|
||||
/**
|
||||
* Represents a user's personal profile.
|
||||
|
@ -96,10 +100,10 @@ data class AccountJson(
|
|||
@Serializable
|
||||
data class Tokens(
|
||||
@SerialName("accessToken")
|
||||
val accessToken: String,
|
||||
val accessToken: String?,
|
||||
|
||||
@SerialName("refreshToken")
|
||||
val refreshToken: String,
|
||||
val refreshToken: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,13 +83,11 @@ class AuthRepositoryImpl constructor(
|
|||
.userStateFlow
|
||||
.map { userState ->
|
||||
userState
|
||||
?.activeAccount
|
||||
?.tokens
|
||||
?.accessToken
|
||||
?.let {
|
||||
AuthState.Authenticated(
|
||||
userState
|
||||
.activeAccount
|
||||
.tokens
|
||||
.accessToken,
|
||||
)
|
||||
AuthState.Authenticated(accessToken = it)
|
||||
}
|
||||
?: AuthState.Unauthenticated
|
||||
}
|
||||
|
@ -191,6 +189,13 @@ class AuthRepositoryImpl constructor(
|
|||
.environment
|
||||
.environmentUrlData,
|
||||
)
|
||||
// Check for existing organization keys for a soft-logout account.
|
||||
// We can separately unlock the vault for organization data after receiving
|
||||
// the sync response if this data is currently absent.
|
||||
val organizationKeys =
|
||||
authDiskSource.getOrganizationKeys(
|
||||
userId = userStateJson.activeUserId,
|
||||
)
|
||||
vaultRepository.clearUnlockedData()
|
||||
vaultRepository.unlockVault(
|
||||
userId = userStateJson.activeUserId,
|
||||
|
@ -199,9 +204,7 @@ class AuthRepositoryImpl constructor(
|
|||
userKey = loginResponse.key,
|
||||
privateKey = loginResponse.privateKey,
|
||||
masterPassword = password,
|
||||
// We can separately unlock the vault for organization data after
|
||||
// receiving the sync response.
|
||||
organizationKeys = null,
|
||||
organizationKeys = organizationKeys,
|
||||
)
|
||||
authDiskSource.userState = userStateJson
|
||||
authDiskSource.storeUserKey(
|
||||
|
@ -228,10 +231,15 @@ class AuthRepositoryImpl constructor(
|
|||
)
|
||||
|
||||
override fun refreshAccessTokenSynchronously(userId: String): Result<RefreshTokenResponseJson> {
|
||||
val refreshAccount = authDiskSource.userState?.accounts?.get(userId)
|
||||
val refreshToken = authDiskSource
|
||||
.userState
|
||||
?.accounts
|
||||
?.get(userId)
|
||||
?.tokens
|
||||
?.refreshToken
|
||||
?: return IllegalStateException("Must be logged in.").asFailure()
|
||||
return identityService
|
||||
.refreshTokenSynchronously(refreshAccount.tokens.refreshToken)
|
||||
.refreshTokenSynchronously(refreshToken)
|
||||
.onSuccess {
|
||||
// Update the existing UserState with updated token information
|
||||
authDiskSource.userState = it.toUserStateJson(
|
||||
|
|
|
@ -42,6 +42,8 @@ data class UserState(
|
|||
* @property avatarColorHex Hex color value for a user's avatar in the "#AARRGGBB" format.
|
||||
* @property environment The [Environment] associated with the user's account.
|
||||
* @property isPremium `true` if the account has a premium membership.
|
||||
* @property isLoggedIn `true` if the account is logged in, or `false` if it requires additional
|
||||
* authentication to view their vault.
|
||||
* @property isVaultUnlocked Whether or not the user's vault is currently unlocked.
|
||||
* @property organizations List of [Organization]s the user is associated with, if any.
|
||||
*/
|
||||
|
@ -52,6 +54,7 @@ data class UserState(
|
|||
val avatarColorHex: String,
|
||||
val environment: Environment,
|
||||
val isPremium: Boolean,
|
||||
val isLoggedIn: Boolean,
|
||||
val isVaultUnlocked: Boolean,
|
||||
val organizations: List<Organization>,
|
||||
)
|
||||
|
|
|
@ -66,6 +66,7 @@ fun UserStateJson.toUserState(
|
|||
.environmentUrlData
|
||||
.toEnvironmentUrlsOrDefault(),
|
||||
isPremium = accountJson.profile.hasPremium == true,
|
||||
isLoggedIn = accountJson.isLoggedIn,
|
||||
isVaultUnlocked = userId in vaultState.unlockedVaultUserIds,
|
||||
organizations = userOrganizationsList
|
||||
.find { it.userId == userId }
|
||||
|
|
|
@ -53,7 +53,9 @@ class LandingViewModel @Inject constructor(
|
|||
get() {
|
||||
val currentEmail = state.emailInput
|
||||
val accountSummaries = state.accountSummaries
|
||||
return accountSummaries.find { it.email == currentEmail }
|
||||
return accountSummaries
|
||||
.find { it.email == currentEmail }
|
||||
?.takeUnless { !it.isLoggedIn }
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
|
@ -25,6 +25,7 @@ data class AccountSummary(
|
|||
val avatarColorHex: String,
|
||||
val environmentLabel: String,
|
||||
val isActive: Boolean,
|
||||
val isLoggedIn: Boolean,
|
||||
val isVaultUnlocked: Boolean,
|
||||
) : Parcelable {
|
||||
|
||||
|
@ -40,6 +41,7 @@ data class AccountSummary(
|
|||
val status: Status
|
||||
get() = when {
|
||||
isActive -> Status.ACTIVE
|
||||
!isLoggedIn -> Status.LOGGED_OUT
|
||||
isVaultUnlocked -> Status.UNLOCKED
|
||||
else -> Status.LOCKED
|
||||
}
|
||||
|
@ -58,6 +60,11 @@ data class AccountSummary(
|
|||
*/
|
||||
LOCKED,
|
||||
|
||||
/**
|
||||
* The account is currently logged out.
|
||||
*/
|
||||
LOGGED_OUT,
|
||||
|
||||
/**
|
||||
* The account is currently unlocked.
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,10 @@ class RootNavViewModel @Inject constructor(
|
|||
) {
|
||||
val userState = action.userState
|
||||
val updatedRootNavState = when {
|
||||
userState == null || userState.hasPendingAccountAddition -> RootNavState.Auth
|
||||
userState == null ||
|
||||
!userState.activeAccount.isLoggedIn ||
|
||||
userState.hasPendingAccountAddition -> RootNavState.Auth
|
||||
|
||||
userState.activeAccount.isVaultUnlocked -> {
|
||||
RootNavState.VaultUnlocked(
|
||||
activeUserId = userState.activeAccount.userId,
|
||||
|
|
|
@ -37,6 +37,7 @@ val AccountSummary.iconRes: Int
|
|||
get() = when (this.status) {
|
||||
AccountSummary.Status.ACTIVE -> R.drawable.ic_check_mark
|
||||
AccountSummary.Status.LOCKED -> R.drawable.ic_locked
|
||||
AccountSummary.Status.LOGGED_OUT -> R.drawable.ic_locked
|
||||
AccountSummary.Status.UNLOCKED -> R.drawable.ic_unlocked
|
||||
}
|
||||
|
||||
|
@ -48,5 +49,6 @@ val AccountSummary.supportingTextResOrNull: Int?
|
|||
get() = when (this.status) {
|
||||
AccountSummary.Status.ACTIVE -> null
|
||||
AccountSummary.Status.LOCKED -> R.string.account_locked
|
||||
AccountSummary.Status.LOGGED_OUT -> R.string.account_logged_out
|
||||
AccountSummary.Status.UNLOCKED -> R.string.account_unlocked
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ fun UserState.Account.toAccountSummary(
|
|||
avatarColorHex = this.avatarColorHex,
|
||||
environmentLabel = this.environment.label,
|
||||
isActive = isActive,
|
||||
isLoggedIn = this.isLoggedIn,
|
||||
isVaultUnlocked = this.isVaultUnlocked,
|
||||
)
|
||||
|
||||
|
|
|
@ -594,6 +594,89 @@ class AuthRepositoryTest {
|
|||
verify { vaultRepository.clearUnlockedData() }
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `login get token succeeds when the current user is in a soft-logout state should use existing organization keys when unlocking the vault`() =
|
||||
runTest {
|
||||
val successResponse = GET_TOKEN_RESPONSE_SUCCESS
|
||||
coEvery {
|
||||
accountsService.preLogin(email = EMAIL)
|
||||
} returns Result.success(PRE_LOGIN_SUCCESS)
|
||||
coEvery {
|
||||
identityService.getToken(
|
||||
email = EMAIL,
|
||||
passwordHash = PASSWORD_HASH,
|
||||
captchaToken = null,
|
||||
uniqueAppId = UNIQUE_APP_ID,
|
||||
)
|
||||
}
|
||||
.returns(Result.success(successResponse))
|
||||
coEvery {
|
||||
vaultRepository.unlockVault(
|
||||
userId = USER_ID_1,
|
||||
email = EMAIL,
|
||||
kdf = ACCOUNT_1.profile.toSdkParams(),
|
||||
userKey = successResponse.key,
|
||||
privateKey = successResponse.privateKey,
|
||||
organizationKeys = ORGANIZATION_KEYS,
|
||||
masterPassword = PASSWORD,
|
||||
)
|
||||
} returns VaultUnlockResult.Success
|
||||
coEvery { vaultRepository.sync() } just runs
|
||||
every {
|
||||
GET_TOKEN_RESPONSE_SUCCESS.toUserState(
|
||||
previousUserState = null,
|
||||
environmentUrlData = EnvironmentUrlDataJson.DEFAULT_US,
|
||||
)
|
||||
} returns SINGLE_USER_STATE_1
|
||||
// Users in a soft-logout state have some existing data stored to disk from previous
|
||||
// sync requests.
|
||||
fakeAuthDiskSource.storeOrganizationKeys(
|
||||
userId = USER_ID_1,
|
||||
organizationKeys = ORGANIZATION_KEYS,
|
||||
)
|
||||
|
||||
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
|
||||
|
||||
assertEquals(LoginResult.Success, result)
|
||||
assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value)
|
||||
coVerify { accountsService.preLogin(email = EMAIL) }
|
||||
fakeAuthDiskSource.assertPrivateKey(
|
||||
userId = USER_ID_1,
|
||||
privateKey = "privateKey",
|
||||
)
|
||||
fakeAuthDiskSource.assertUserKey(
|
||||
userId = USER_ID_1,
|
||||
userKey = "key",
|
||||
)
|
||||
coVerify {
|
||||
identityService.getToken(
|
||||
email = EMAIL,
|
||||
passwordHash = PASSWORD_HASH,
|
||||
captchaToken = null,
|
||||
uniqueAppId = UNIQUE_APP_ID,
|
||||
)
|
||||
vaultRepository.unlockVault(
|
||||
userId = USER_ID_1,
|
||||
email = EMAIL,
|
||||
kdf = ACCOUNT_1.profile.toSdkParams(),
|
||||
userKey = successResponse.key,
|
||||
privateKey = successResponse.privateKey,
|
||||
organizationKeys = ORGANIZATION_KEYS,
|
||||
masterPassword = PASSWORD,
|
||||
)
|
||||
vaultRepository.sync()
|
||||
}
|
||||
assertEquals(
|
||||
SINGLE_USER_STATE_1,
|
||||
fakeAuthDiskSource.userState,
|
||||
)
|
||||
assertNull(repository.specialCircumstance)
|
||||
verify { settingsRepository.setDefaultsIfNecessary(userId = USER_ID_1) }
|
||||
verify(exactly = 0) { vaultRepository.lockVaultIfNecessary(any()) }
|
||||
verify { vaultRepository.clearUnlockedData() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login get token returns captcha request should return CaptchaRequired`() = runTest {
|
||||
coEvery { accountsService.preLogin(EMAIL) } returns Result.success(PRE_LOGIN_SUCCESS)
|
||||
|
@ -981,7 +1064,7 @@ class AuthRepositoryTest {
|
|||
kdf = ACCOUNT_1.profile.toSdkParams(),
|
||||
userKey = successResponse.key,
|
||||
privateKey = successResponse.privateKey,
|
||||
organizationKeys = null,
|
||||
organizationKeys = ORGANIZATION_KEYS,
|
||||
masterPassword = PASSWORD,
|
||||
)
|
||||
} returns VaultUnlockResult.Success
|
||||
|
|
|
@ -104,6 +104,7 @@ class UserStateJsonExtensionsTest {
|
|||
avatarColorHex = "activeAvatarColorHex",
|
||||
environment = Environment.Eu,
|
||||
isPremium = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -125,7 +126,10 @@ class UserStateJsonExtensionsTest {
|
|||
every { avatarColorHex } returns "activeAvatarColorHex"
|
||||
every { hasPremium } returns null
|
||||
},
|
||||
tokens = mockk(),
|
||||
tokens = AccountJson.Tokens(
|
||||
accessToken = "accessToken",
|
||||
refreshToken = "refreshToken",
|
||||
),
|
||||
settings = AccountJson.Settings(
|
||||
environmentUrlData = EnvironmentUrlDataJson.DEFAULT_EU,
|
||||
),
|
||||
|
@ -167,6 +171,7 @@ class UserStateJsonExtensionsTest {
|
|||
avatarColorHex = "#ffecbc49",
|
||||
environment = Environment.Eu,
|
||||
isPremium = true,
|
||||
isLoggedIn = false,
|
||||
isVaultUnlocked = false,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -189,7 +194,10 @@ class UserStateJsonExtensionsTest {
|
|||
every { avatarColorHex } returns null
|
||||
every { hasPremium } returns true
|
||||
},
|
||||
tokens = mockk(),
|
||||
tokens = AccountJson.Tokens(
|
||||
accessToken = null,
|
||||
refreshToken = null,
|
||||
),
|
||||
settings = AccountJson.Settings(
|
||||
environmentUrlData = EnvironmentUrlDataJson.DEFAULT_EU,
|
||||
),
|
||||
|
|
|
@ -432,6 +432,7 @@ private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
)
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -189,7 +190,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `ContinueButtonClick with an email input matching an existing account should show the account already added dialog`() {
|
||||
fun `ContinueButtonClick with an email input matching an existing account that is logged in should show the account already added dialog`() {
|
||||
val rememberedEmail = "active@bitwarden.com"
|
||||
val activeAccount = UserState.Account(
|
||||
userId = "activeUserId",
|
||||
|
@ -198,6 +199,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
)
|
||||
|
@ -234,6 +236,55 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `ContinueButtonClick with an email input matching an existing account that is logged out should emit NavigateToLogin`() =
|
||||
runTest {
|
||||
val rememberedEmail = "active@bitwarden.com"
|
||||
val activeAccount = UserState.Account(
|
||||
userId = "activeUserId",
|
||||
name = "name",
|
||||
email = rememberedEmail,
|
||||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = false,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
)
|
||||
val userState = UserState(
|
||||
activeUserId = "activeUserId",
|
||||
accounts = listOf(activeAccount),
|
||||
)
|
||||
val viewModel = createViewModel(
|
||||
rememberedEmail = rememberedEmail,
|
||||
userState = userState,
|
||||
)
|
||||
val accountSummaries = userState.toAccountSummaries()
|
||||
val initialState = DEFAULT_STATE.copy(
|
||||
emailInput = rememberedEmail,
|
||||
isContinueButtonEnabled = true,
|
||||
isRememberMeEnabled = true,
|
||||
accountSummaries = accountSummaries,
|
||||
)
|
||||
assertEquals(
|
||||
initialState,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LandingAction.ContinueButtonClick)
|
||||
assertEquals(
|
||||
LandingEvent.NavigateToLogin(rememberedEmail),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
initialState,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CreateAccountClick should emit NavigateToCreateAccount`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
|
|
@ -288,6 +288,7 @@ private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
)
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
|
|
@ -273,6 +273,7 @@ private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
)
|
||||
|
||||
|
@ -283,6 +284,7 @@ private val LOCKED_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#00aaaa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
)
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#00aaaa",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -137,6 +138,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#00aaaa",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -156,6 +158,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#00aaaa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
),
|
||||
),
|
||||
|
@ -352,6 +355,7 @@ private val DEFAULT_STATE: VaultUnlockState = VaultUnlockState(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
),
|
||||
|
@ -373,6 +377,7 @@ private val DEFAULT_USER_STATE = UserState(
|
|||
environment = Environment.Us,
|
||||
avatarColorHex = "#aa00aa",
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
|
|
@ -36,6 +36,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -62,6 +63,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
|
|
@ -1737,6 +1737,7 @@ private val DEFAULT_USER_STATE = UserState(
|
|||
environment = Environment.Us,
|
||||
avatarColorHex = "#aa00aa",
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
|
|
@ -823,6 +823,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#ff00ff",
|
||||
environment = Environment.Us,
|
||||
isPremium = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
)
|
||||
|
|
|
@ -795,6 +795,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#ff00ff",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
|
|
@ -1031,6 +1031,7 @@ private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
)
|
||||
|
||||
|
@ -1041,6 +1042,7 @@ private val LOCKED_ACCOUNT_SUMMARY = AccountSummary(
|
|||
avatarColorHex = "#00aaaa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
)
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#00aaaa",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -154,6 +155,7 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||
avatarColorHex = "#00aaaa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
),
|
||||
|
@ -1030,6 +1032,7 @@ private val DEFAULT_USER_STATE = UserState(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -1040,6 +1043,7 @@ private val DEFAULT_USER_STATE = UserState(
|
|||
avatarColorHex = "#00aaaa",
|
||||
environment = Environment.Us,
|
||||
isPremium = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
organizations = emptyList(),
|
||||
),
|
||||
|
@ -1062,6 +1066,7 @@ private fun createMockVaultState(
|
|||
avatarColorHex = "#aa00aa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
AccountSummary(
|
||||
|
@ -1071,6 +1076,7 @@ private fun createMockVaultState(
|
|||
avatarColorHex = "#00aaaa",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -68,6 +68,17 @@ class AccountSummaryExtensionsTest {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iconRes returns a locked lock for logged out accounts`() {
|
||||
assertEquals(
|
||||
R.drawable.ic_locked,
|
||||
mockk<AccountSummary>() {
|
||||
every { status } returns AccountSummary.Status.LOGGED_OUT
|
||||
}
|
||||
.iconRes,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iconRes returns an unlocked lock for unlocked accounts`() {
|
||||
assertEquals(
|
||||
|
@ -100,6 +111,17 @@ class AccountSummaryExtensionsTest {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `supportingTextResOrNull returns Logged Out for logged out accounts`() {
|
||||
assertEquals(
|
||||
R.string.account_logged_out,
|
||||
mockk<AccountSummary>() {
|
||||
every { status } returns AccountSummary.Status.LOGGED_OUT
|
||||
}
|
||||
.supportingTextResOrNull,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `supportingTextResOrNull returns Unlocked for unlocked accounts`() {
|
||||
assertEquals(
|
||||
|
|
|
@ -23,6 +23,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "activeAvatarColorHex",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
AccountSummary(
|
||||
|
@ -32,6 +33,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "lockedAvatarColorHex",
|
||||
environmentLabel = "bitwarden.eu",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
),
|
||||
AccountSummary(
|
||||
|
@ -41,8 +43,19 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "unlockedAvatarColorHex",
|
||||
environmentLabel = "vault.qa.bitwarden.pw",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
AccountSummary(
|
||||
userId = "loggedOutUserId",
|
||||
name = "loggedOutName",
|
||||
email = "loggedOutEmail",
|
||||
avatarColorHex = "loggedOutAvatarColorHex",
|
||||
environmentLabel = "vault.qa.bitwarden.pw",
|
||||
isActive = false,
|
||||
isLoggedIn = false,
|
||||
isVaultUnlocked = false,
|
||||
),
|
||||
),
|
||||
UserState(
|
||||
activeUserId = "activeUserId",
|
||||
|
@ -54,6 +67,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "activeAvatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -69,6 +83,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "lockedAvatarColorHex",
|
||||
environment = Environment.Eu,
|
||||
isPremium = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -88,6 +103,7 @@ class UserStateExtensionsTest {
|
|||
),
|
||||
),
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -96,6 +112,26 @@ class UserStateExtensionsTest {
|
|||
),
|
||||
),
|
||||
),
|
||||
UserState.Account(
|
||||
userId = "loggedOutUserId",
|
||||
name = "loggedOutName",
|
||||
email = "loggedOutEmail",
|
||||
avatarColorHex = "loggedOutAvatarColorHex",
|
||||
environment = Environment.SelfHosted(
|
||||
environmentUrlData = EnvironmentUrlDataJson(
|
||||
base = "https://vault.qa.bitwarden.pw",
|
||||
),
|
||||
),
|
||||
isPremium = true,
|
||||
isLoggedIn = false,
|
||||
isVaultUnlocked = false,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
id = "organizationId",
|
||||
name = "organizationName",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toAccountSummaries(),
|
||||
|
@ -112,6 +148,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
UserState.Account(
|
||||
|
@ -121,6 +158,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -143,6 +181,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
),
|
||||
UserState.Account(
|
||||
|
@ -152,6 +191,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = false,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = false,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -175,6 +215,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environmentLabel = "bitwarden.com",
|
||||
isActive = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
UserState(
|
||||
|
@ -187,6 +228,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
@ -211,6 +253,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = emptyList(),
|
||||
)
|
||||
|
@ -244,6 +287,7 @@ class UserStateExtensionsTest {
|
|||
avatarColorHex = "avatarColorHex",
|
||||
environment = Environment.Us,
|
||||
isPremium = true,
|
||||
isLoggedIn = true,
|
||||
isVaultUnlocked = true,
|
||||
organizations = listOf(
|
||||
Organization(
|
||||
|
|
Loading…
Add table
Reference in a new issue