mirror of
https://github.com/bitwarden/android.git
synced 2024-11-27 12:00:19 +03:00
BIT-1148: Add storage for blocked autofill URIs (#657)
This commit is contained in:
parent
a87bcd28ff
commit
840f675736
8 changed files with 163 additions and 0 deletions
|
@ -102,4 +102,17 @@ interface SettingsDiskSource {
|
|||
* Stores the given [isInlineAutofillEnabled] value for the given [userId].
|
||||
*/
|
||||
fun storeInlineAutofillEnabled(userId: String, isInlineAutofillEnabled: Boolean?)
|
||||
|
||||
/**
|
||||
* Gets a list of blocked autofill URI's for the given [userId].
|
||||
*/
|
||||
fun getBlockedAutofillUris(userId: String): List<String>?
|
||||
|
||||
/**
|
||||
* Stores the list of [blockedAutofillUris] for the given [userId].
|
||||
*/
|
||||
fun storeBlockedAutofillUris(
|
||||
userId: String,
|
||||
blockedAutofillUris: List<String>?,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,11 +9,14 @@ import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppThem
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.onSubscription
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private const val APP_LANGUAGE_KEY = "$BASE_KEY:appLocale"
|
||||
private const val APP_THEME_KEY = "$BASE_KEY:theme"
|
||||
private const val PULL_TO_REFRESH_KEY = "$BASE_KEY:syncOnRefresh"
|
||||
private const val INLINE_AUTOFILL_ENABLED_KEY = "$BASE_KEY:inlineAutofillEnabled"
|
||||
private const val BLOCKED_AUTOFILL_URIS_KEY = "$BASE_KEY:autofillBlacklistedUris"
|
||||
private const val VAULT_TIMEOUT_ACTION_KEY = "$BASE_KEY:vaultTimeoutAction"
|
||||
private const val VAULT_TIME_IN_MINUTES_KEY = "$BASE_KEY:vaultTimeout"
|
||||
private const val DISABLE_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon"
|
||||
|
@ -24,6 +27,7 @@ private const val DISABLE_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon"
|
|||
@Suppress("TooManyFunctions")
|
||||
class SettingsDiskSourceImpl(
|
||||
val sharedPreferences: SharedPreferences,
|
||||
private val json: Json,
|
||||
) : BaseDiskSource(sharedPreferences = sharedPreferences),
|
||||
SettingsDiskSource {
|
||||
private val mutableAppThemeFlow =
|
||||
|
@ -87,6 +91,7 @@ class SettingsDiskSourceImpl(
|
|||
storeVaultTimeoutAction(userId = userId, vaultTimeoutAction = null)
|
||||
storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null)
|
||||
storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null)
|
||||
storeBlockedAutofillUris(userId = userId, blockedAutofillUris = null)
|
||||
}
|
||||
|
||||
override fun getVaultTimeoutInMinutes(userId: String): Int? =
|
||||
|
@ -152,6 +157,21 @@ class SettingsDiskSourceImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override fun getBlockedAutofillUris(userId: String): List<String>? =
|
||||
getString(key = "${BLOCKED_AUTOFILL_URIS_KEY}_$userId")?.let {
|
||||
json.decodeFromString(it)
|
||||
}
|
||||
|
||||
override fun storeBlockedAutofillUris(
|
||||
userId: String,
|
||||
blockedAutofillUris: List<String>?,
|
||||
) {
|
||||
putString(
|
||||
key = "${BLOCKED_AUTOFILL_URIS_KEY}_$userId",
|
||||
value = blockedAutofillUris?.let { json.encodeToString(it) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun getMutableVaultTimeoutActionFlow(
|
||||
userId: String,
|
||||
): MutableSharedFlow<VaultTimeoutAction?> =
|
||||
|
|
|
@ -46,8 +46,10 @@ object PlatformDiskModule {
|
|||
@Singleton
|
||||
fun provideSettingsDiskSource(
|
||||
@UnencryptedPreferences sharedPreferences: SharedPreferences,
|
||||
json: Json,
|
||||
): SettingsDiskSource =
|
||||
SettingsDiskSourceImpl(
|
||||
sharedPreferences = sharedPreferences,
|
||||
json = json,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,11 @@ interface SettingsRepository {
|
|||
*/
|
||||
var isInlineAutofillEnabled: Boolean
|
||||
|
||||
/**
|
||||
* A list of blocked autofill URI's for the current user.
|
||||
*/
|
||||
var blockedAutofillUris: List<String>
|
||||
|
||||
/**
|
||||
* Sets default values for various settings for the given [userId] if necessary. This is
|
||||
* typically used when logging into a new account.
|
||||
|
|
|
@ -109,6 +109,18 @@ class SettingsRepositoryImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override var blockedAutofillUris: List<String>
|
||||
get() = activeUserId
|
||||
?.let { settingsDiskSource.getBlockedAutofillUris(userId = it) }
|
||||
?: emptyList()
|
||||
set(value) {
|
||||
val userId = activeUserId ?: return
|
||||
settingsDiskSource.storeBlockedAutofillUris(
|
||||
userId = userId,
|
||||
blockedAutofillUris = value,
|
||||
)
|
||||
}
|
||||
|
||||
override fun setDefaultsIfNecessary(userId: String) {
|
||||
// Set Vault Settings defaults
|
||||
if (!isVaultTimeoutActionSet(userId = userId)) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
|
|||
import androidx.core.content.edit
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.di.PlatformNetworkModule
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
|
@ -15,9 +16,11 @@ import org.junit.jupiter.api.Test
|
|||
|
||||
class SettingsDiskSourceTest {
|
||||
private val fakeSharedPreferences = FakeSharedPreferences()
|
||||
private val json = PlatformNetworkModule.providesJson()
|
||||
|
||||
private val settingsDiskSource = SettingsDiskSourceImpl(
|
||||
sharedPreferences = fakeSharedPreferences,
|
||||
json = json,
|
||||
)
|
||||
|
||||
@Test
|
||||
|
@ -78,6 +81,10 @@ class SettingsDiskSourceTest {
|
|||
userId = userId,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
settingsDiskSource.storeBlockedAutofillUris(
|
||||
userId = userId,
|
||||
blockedAutofillUris = listOf("www.example.com"),
|
||||
)
|
||||
|
||||
settingsDiskSource.clearData(userId = userId)
|
||||
|
||||
|
@ -85,6 +92,7 @@ class SettingsDiskSourceTest {
|
|||
assertNull(settingsDiskSource.getVaultTimeoutAction(userId = userId))
|
||||
assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = userId))
|
||||
assertNull(settingsDiskSource.getInlineAutofillEnabled(userId = userId))
|
||||
assertNull(settingsDiskSource.getBlockedAutofillUris(userId = userId))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -441,4 +449,62 @@ class SettingsDiskSourceTest {
|
|||
)
|
||||
assertFalse(fakeSharedPreferences.contains(inlineAutofillEnabledKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getBlockedAutofillUris should pull from SharedPreferences`() {
|
||||
val blockedAutofillUrisBaseKey = "bwPreferencesStorage:autofillBlacklistedUris"
|
||||
val mockUserId = "mockUserId"
|
||||
val mockBlockedAutofillUris = listOf(
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com",
|
||||
)
|
||||
fakeSharedPreferences
|
||||
.edit {
|
||||
putString(
|
||||
"${blockedAutofillUrisBaseKey}_$mockUserId",
|
||||
"""
|
||||
[
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com"
|
||||
]
|
||||
"""
|
||||
.trimIndent(),
|
||||
)
|
||||
}
|
||||
val actual = settingsDiskSource.getBlockedAutofillUris(userId = mockUserId)
|
||||
assertEquals(
|
||||
mockBlockedAutofillUris,
|
||||
actual,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storeBlockedAutofillUris should update SharedPreferences`() {
|
||||
val blockedAutofillUrisBaseKey = "bwPreferencesStorage:autofillBlacklistedUris"
|
||||
val mockUserId = "mockUserId"
|
||||
val mockBlockedAutofillUris = listOf(
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com",
|
||||
)
|
||||
settingsDiskSource.storeBlockedAutofillUris(
|
||||
userId = mockUserId,
|
||||
blockedAutofillUris = mockBlockedAutofillUris,
|
||||
)
|
||||
val actual = fakeSharedPreferences.getString(
|
||||
"${blockedAutofillUrisBaseKey}_$mockUserId",
|
||||
null,
|
||||
)
|
||||
assertEquals(
|
||||
json.parseToJsonElement(
|
||||
"""
|
||||
[
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com"
|
||||
]
|
||||
"""
|
||||
.trimIndent(),
|
||||
),
|
||||
json.parseToJsonElement(requireNotNull(actual)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
|
||||
private val storedPullToRefreshEnabled = mutableMapOf<String, Boolean?>()
|
||||
private val storedInlineAutofillEnabled = mutableMapOf<String, Boolean?>()
|
||||
private val storedBlockedAutofillUris = mutableMapOf<String, List<String>?>()
|
||||
|
||||
private var storedIsIconLoadingDisabled: Boolean? = null
|
||||
|
||||
|
@ -69,6 +70,7 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
storedVaultTimeoutInMinutes.remove(userId)
|
||||
storedPullToRefreshEnabled.remove(userId)
|
||||
storedInlineAutofillEnabled.remove(userId)
|
||||
storedBlockedAutofillUris.remove(userId)
|
||||
|
||||
mutableVaultTimeoutActionsFlowMap.remove(userId)
|
||||
mutableVaultTimeoutInMinutesFlowMap.remove(userId)
|
||||
|
@ -126,6 +128,16 @@ class FakeSettingsDiskSource : SettingsDiskSource {
|
|||
storedInlineAutofillEnabled[userId] = isInlineAutofillEnabled
|
||||
}
|
||||
|
||||
override fun getBlockedAutofillUris(userId: String): List<String>? =
|
||||
storedBlockedAutofillUris[userId]
|
||||
|
||||
override fun storeBlockedAutofillUris(
|
||||
userId: String,
|
||||
blockedAutofillUris: List<String>?,
|
||||
) {
|
||||
storedBlockedAutofillUris[userId] = blockedAutofillUris
|
||||
}
|
||||
|
||||
//region Private helper functions
|
||||
|
||||
private fun getMutableVaultTimeoutActionsFlow(
|
||||
|
|
|
@ -356,6 +356,39 @@ class SettingsRepositoryTest {
|
|||
assertTrue(fakeSettingsDiskSource.getInlineAutofillEnabled(userId = userId)!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blockedAutofillUris should pull from and update SettingsDiskSource`() {
|
||||
val userId = "userId"
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
assertEquals(
|
||||
emptyList<String>(),
|
||||
settingsRepository.blockedAutofillUris,
|
||||
)
|
||||
|
||||
// Updates to the disk source change the repository value.
|
||||
fakeSettingsDiskSource.storeBlockedAutofillUris(
|
||||
userId = userId,
|
||||
blockedAutofillUris = listOf(
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com",
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
listOf(
|
||||
"https://www.example1.com",
|
||||
"https://www.example2.com",
|
||||
),
|
||||
settingsRepository.blockedAutofillUris,
|
||||
)
|
||||
|
||||
// Updates to the repository change the disk source value
|
||||
settingsRepository.blockedAutofillUris = emptyList()
|
||||
assertEquals(
|
||||
emptyList<String>(),
|
||||
fakeSettingsDiskSource.getBlockedAutofillUris(userId = userId),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPullToRefreshEnabledFlow should react to changes in SettingsDiskSource`() = runTest {
|
||||
val userId = "userId"
|
||||
|
|
Loading…
Reference in a new issue