mirror of
https://github.com/bitwarden/android.git
synced 2025-02-17 04:19:54 +03:00
Add checks for locked vault to autofill (#703)
This commit is contained in:
parent
6c003c4102
commit
f4fceb175a
6 changed files with 160 additions and 12 deletions
|
@ -18,8 +18,7 @@ class FilledDataBuilderImpl(
|
|||
private val autofillCipherProvider: AutofillCipherProvider,
|
||||
) : FilledDataBuilder {
|
||||
override suspend fun build(autofillRequest: AutofillRequest.Fillable): FilledData {
|
||||
// TODO: determine whether or not the vault is locked (BIT-1296)
|
||||
val isVaultLocked = false
|
||||
val isVaultLocked = autofillCipherProvider.isVaultLocked()
|
||||
|
||||
// Subtract one to make sure there is space for the vault item.
|
||||
val maxCipherInlineSuggestionsCount = autofillRequest.maxInlineSuggestionsCount - 1
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.autofill.di
|
|||
|
||||
import android.content.Context
|
||||
import android.view.autofill.AutofillManager
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.builder.FillResponseBuilder
|
||||
import com.x8bit.bitwarden.data.autofill.builder.FillResponseBuilderImpl
|
||||
import com.x8bit.bitwarden.data.autofill.builder.FilledDataBuilder
|
||||
|
@ -14,6 +15,7 @@ import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
|
|||
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProviderImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
@ -43,7 +45,14 @@ object AutofillModule {
|
|||
)
|
||||
|
||||
@Provides
|
||||
fun providesAutofillCipherProvider(): AutofillCipherProvider = AutofillCipherProviderImpl()
|
||||
fun providesAutofillCipherProvider(
|
||||
authRepository: AuthRepository,
|
||||
vaultRepository: VaultRepository,
|
||||
): AutofillCipherProvider =
|
||||
AutofillCipherProviderImpl(
|
||||
authRepository = authRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
fun providesAutofillProcessor(
|
||||
|
|
|
@ -6,6 +6,12 @@ import com.x8bit.bitwarden.data.autofill.model.AutofillCipher
|
|||
* A service for getting [AutofillCipher]s.
|
||||
*/
|
||||
interface AutofillCipherProvider {
|
||||
/**
|
||||
* Returns `true` if the vault for the current user is locked. This suspends in order to return
|
||||
* a value only after any unlocking vaults have fully unlocked (or failed to do so).
|
||||
*/
|
||||
suspend fun isVaultLocked(): Boolean
|
||||
|
||||
/**
|
||||
* Get all [AutofillCipher.Card]s for the current user.
|
||||
*/
|
||||
|
|
|
@ -1,22 +1,40 @@
|
|||
package com.x8bit.bitwarden.data.autofill.provider
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* The default [AutofillCipherProvider] implementation. This service is used for getting currrent
|
||||
* [AutofillCipher]s.
|
||||
*/
|
||||
class AutofillCipherProviderImpl : AutofillCipherProvider {
|
||||
class AutofillCipherProviderImpl(
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
) : AutofillCipherProvider {
|
||||
private val activeUserId: String? get() = authRepository.activeUserId
|
||||
|
||||
override suspend fun isVaultLocked(): Boolean {
|
||||
val userId = activeUserId ?: return true
|
||||
|
||||
// Wait for any unlocking actions to finish. This can be relevant on startup for Never lock
|
||||
// accounts.
|
||||
vaultRepository.vaultStateFlow.first { userId !in it.unlockingVaultUserIds }
|
||||
|
||||
return !vaultRepository.isVaultUnlocked(userId = userId)
|
||||
}
|
||||
|
||||
override suspend fun getCardAutofillCiphers(): List<AutofillCipher.Card> {
|
||||
// TODO: fulfill with real ciphers (BIT-1294)
|
||||
return cardCiphers
|
||||
return if (isVaultLocked()) emptyList() else cardCiphers
|
||||
}
|
||||
|
||||
override suspend fun getLoginAutofillCiphers(
|
||||
uri: String,
|
||||
): List<AutofillCipher.Login> {
|
||||
// TODO: fulfill with real ciphers (BIT-1294)
|
||||
return loginCiphers
|
||||
return if (isVaultLocked()) emptyList() else loginCiphers
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@ import org.junit.jupiter.api.Test
|
|||
class FilledDataBuilderTest {
|
||||
private lateinit var filledDataBuilder: FilledDataBuilder
|
||||
|
||||
private val autofillCipherProvider: AutofillCipherProvider = mockk()
|
||||
private val autofillCipherProvider: AutofillCipherProvider = mockk {
|
||||
coEvery { isVaultLocked() } returns false
|
||||
}
|
||||
|
||||
private val autofillId: AutofillId = mockk()
|
||||
private val autofillViewData = AutofillView.Data(
|
||||
|
|
|
@ -1,40 +1,154 @@
|
|||
package com.x8bit.bitwarden.data.autofill.processor
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillCipher
|
||||
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
|
||||
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProviderImpl
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AutofillCipherProviderTest {
|
||||
|
||||
private val authRepository: AuthRepository = mockk {
|
||||
every { activeUserId } returns ACTIVE_USER_ID
|
||||
}
|
||||
private val mutableVaultStateFlow = MutableStateFlow<VaultState>(
|
||||
VaultState(
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
),
|
||||
)
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { vaultStateFlow } returns mutableVaultStateFlow
|
||||
every { isVaultUnlocked(ACTIVE_USER_ID) } answers {
|
||||
ACTIVE_USER_ID in mutableVaultStateFlow.value.unlockedVaultUserIds
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var autofillCipherProvider: AutofillCipherProvider
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
autofillCipherProvider = AutofillCipherProviderImpl()
|
||||
autofillCipherProvider = AutofillCipherProviderImpl(
|
||||
authRepository = authRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `getCardAutofillCiphers should return default list of card ciphers`() = runTest {
|
||||
fun `isVaultLocked when there is no active user should return true`() =
|
||||
runTest {
|
||||
every { authRepository.activeUserId } returns null
|
||||
|
||||
val result = async {
|
||||
autofillCipherProvider.isVaultLocked()
|
||||
}
|
||||
|
||||
testScheduler.advanceUntilIdle()
|
||||
assertTrue(result.isCompleted)
|
||||
assertTrue(result.await())
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `isVaultLocked when there is an active user should wait for pending unlocking to finish and return the locked state for that user`() =
|
||||
runTest {
|
||||
every { authRepository.activeUserId } returns ACTIVE_USER_ID
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
)
|
||||
|
||||
val result = async {
|
||||
autofillCipherProvider.isVaultLocked()
|
||||
}
|
||||
|
||||
testScheduler.advanceUntilIdle()
|
||||
assertFalse(result.isCompleted)
|
||||
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
|
||||
testScheduler.advanceUntilIdle()
|
||||
assertTrue(result.isCompleted)
|
||||
|
||||
assertFalse(result.await())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCardAutofillCiphers when unlocked should return default list of card ciphers`() =
|
||||
runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getCardAutofillCiphers()
|
||||
|
||||
assertEquals(CARD_CIPHERS, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCardAutofillCiphers when locked should return an empty list`() = runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getCardAutofillCiphers()
|
||||
|
||||
assertEquals(CARD_CIPHERS, actual)
|
||||
assertEquals(emptyList<AutofillCipher.Card>(), actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLoginAutofillCiphers should return default list of login ciphers`() = runTest {
|
||||
fun `getLoginAutofillCiphers when unlocked should return default list of login ciphers`() =
|
||||
runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getLoginAutofillCiphers(
|
||||
uri = URI,
|
||||
)
|
||||
|
||||
assertEquals(LOGIN_CIPHERS, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLoginAutofillCiphers when locked should return an empty list`() = runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getLoginAutofillCiphers(
|
||||
uri = URI,
|
||||
)
|
||||
|
||||
assertEquals(LOGIN_CIPHERS, actual)
|
||||
assertEquals(emptyList<AutofillCipher.Login>(), actual)
|
||||
}
|
||||
}
|
||||
|
||||
private const val ACTIVE_USER_ID = "activeUserId"
|
||||
|
||||
private val CARD_CIPHERS = listOf(
|
||||
AutofillCipher.Card(
|
||||
cardholderName = "John",
|
||||
|
|
Loading…
Add table
Reference in a new issue