[PM-19845] Migrate BaseDiskSource to data module (#4978)

This commit is contained in:
Patrick Honkonen 2025-04-03 15:34:52 -04:00 committed by GitHub
parent ce0aa7adda
commit 5017e935d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 59 additions and 175 deletions

View File

@ -214,6 +214,7 @@ dependencies {
implementation(files("libs/authenticatorbridge-1.0.0-release.aar"))
implementation(project(":core"))
implementation(project(":data"))
implementation(project(":network"))
implementation(libs.androidx.activity.compose)

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.security.crypto.EncryptedSharedPreferences
import com.bitwarden.data.datasource.disk.BaseDiskSource
/**
* Base class for simplifying interactions with [SharedPreferences] and

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.model.ServerConfig
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onSubscription

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onSubscription

View File

@ -1,6 +1,7 @@
package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
/**

View File

@ -1,6 +1,7 @@
package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.platform.util.getBinaryLongFromZoneDateTime
import com.x8bit.bitwarden.data.platform.util.getZoneDateTimeFromBinaryLong
import java.time.ZonedDateTime

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.platform.manager.model.AppResumeScreenData
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction

View File

@ -2,7 +2,7 @@ package com.x8bit.bitwarden.data.tools.generator.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource
import com.bitwarden.data.datasource.disk.BaseDiskSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
import com.x8bit.bitwarden.data.tools.generator.repository.model.UsernameGenerationOptions
import kotlinx.serialization.json.Json

View File

@ -152,6 +152,7 @@ dependencies {
implementation(files("libs/authenticatorbridge-1.0.0-release.aar"))
implementation(project(":core"))
implementation(project(":data"))
implementation(project(":network"))
implementation(libs.androidx.activity.compose)

View File

@ -1,13 +1,12 @@
package com.bitwarden.authenticator.data.auth.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseEncryptedDiskSource
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseEncryptedDiskSource.Companion.ENCRYPTED_BASE_KEY
private const val AUTHENTICATOR_SYNC_SYMMETRIC_KEY =
"$ENCRYPTED_BASE_KEY:authenticatorSyncSymmetricKey"
private const val LAST_ACTIVE_TIME_KEY = "$BASE_KEY:lastActiveTime"
private const val LAST_ACTIVE_TIME_KEY = "lastActiveTime"
private const val BIOMETRICS_UNLOCK_KEY = "$ENCRYPTED_BASE_KEY:userKeyBiometricUnlock"
/**

View File

@ -1,140 +0,0 @@
package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import androidx.core.content.edit
/**
* Base class for simplifying interactions with [SharedPreferences].
*/
@Suppress("UnnecessaryAbstractClass", "TooManyFunctions")
abstract class BaseDiskSource(
private val sharedPreferences: SharedPreferences,
) {
/**
* Gets the [Boolean] for the given [key] from [SharedPreferences], or return the [default]
* value if that key is not present.
*/
protected fun getBoolean(
key: String,
default: Boolean? = null,
): Boolean? =
if (sharedPreferences.contains(key)) {
sharedPreferences.getBoolean(key, false)
} else {
// Make sure we can return a null value as a default if necessary
default
}
/**
* Puts the [value] in [SharedPreferences] for the given [key] (or removes the key when the
* value is `null`).
*/
protected fun putBoolean(
key: String,
value: Boolean?,
): Unit =
sharedPreferences.edit {
if (value != null) {
putBoolean(key, value)
} else {
remove(key)
}
}
/**
* Gets the [Int] for the given [key] from [SharedPreferences], or return the [default] value
* if that key is not present.
*/
protected fun getInt(
key: String,
default: Int? = null,
): Int? =
if (sharedPreferences.contains(key)) {
sharedPreferences.getInt(key, 0)
} else {
// Make sure we can return a null value as a default if necessary
default
}
/**
* Puts the [value] in [SharedPreferences] for the given [key] (or removes the key when the
* value is `null`).
*/
protected fun putInt(
key: String,
value: Int?,
): Unit =
sharedPreferences.edit {
if (value != null) {
putInt(key, value)
} else {
remove(key)
}
}
/**
* Gets the [Long] for the given [key] from [SharedPreferences], or return the [default] value
* if that key is not present.
*/
protected fun getLong(
key: String,
default: Long? = null,
): Long? =
if (sharedPreferences.contains(key)) {
sharedPreferences.getLong(key, 0)
} else {
// Make sure we can return a null value as a default if necessary
default
}
/**
* Puts the [value] in [SharedPreferences] for the given [key] (or removes the key when the
* value is `null`).
*/
protected fun putLong(
key: String,
value: Long?,
): Unit =
sharedPreferences.edit {
if (value != null) {
putLong(key, value)
} else {
remove(key)
}
}
protected fun getString(
key: String,
default: String? = null,
): String? = sharedPreferences.getString(key, default)
protected fun putString(
key: String,
value: String?,
): Unit = sharedPreferences.edit { putString(key, value) }
protected fun removeWithPrefix(prefix: String) {
sharedPreferences
.all
.keys
.filter { it.startsWith(prefix) }
.forEach { sharedPreferences.edit { remove(it) } }
}
protected fun putStringSet(
key: String,
value: Set<String>?,
): Unit = sharedPreferences.edit {
putStringSet(key, value)
}
protected fun getStringSet(
key: String,
default: Set<String>?,
): Set<String>? = sharedPreferences.getStringSet(key, default)
@Suppress("UndocumentedPublicClass")
companion object {
const val BASE_KEY: String = "bwPreferencesStorage"
}
}

View File

@ -3,6 +3,7 @@ package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.security.crypto.EncryptedSharedPreferences
import com.bitwarden.data.datasource.disk.BaseDiskSource
/**
* Base class for simplifying interactions with [SharedPreferences] and

View File

@ -1,15 +1,15 @@
package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
import com.bitwarden.authenticator.data.platform.datasource.disk.model.ServerConfig
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.bitwarden.data.datasource.disk.BaseDiskSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onSubscription
import kotlinx.serialization.json.Json
private const val SERVER_CONFIGURATIONS = "$BASE_KEY:serverConfigurations"
private const val SERVER_CONFIGURATIONS = "serverConfigurations"
/**
* Primary implementation of [ConfigDiskSource].

View File

@ -1,15 +1,15 @@
package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
import com.bitwarden.authenticator.data.platform.datasource.disk.model.FeatureFlagsConfiguration
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.decodeFromStringOrNull
import com.bitwarden.data.datasource.disk.BaseDiskSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onSubscription
import kotlinx.serialization.json.Json
private const val KEY_FEATURE_FLAGS = "$BASE_KEY:featureFlags"
private const val KEY_FEATURE_FLAGS = "featureFlags"
/**
* Primary implementation of [FeatureFlagDiskSource].

View File

@ -2,6 +2,7 @@ package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.authenticator.data.platform.manager.model.FlagKey
import com.bitwarden.data.datasource.disk.BaseDiskSource
/**
* Default implementation of the [FeatureFlagOverrideDiskSource]

View File

@ -1,29 +1,29 @@
package com.bitwarden.authenticator.data.platform.datasource.disk
import android.content.SharedPreferences
import com.bitwarden.authenticator.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppLanguage
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppTheme
import com.bitwarden.authenticator.ui.platform.feature.settings.data.model.DefaultSaveOption
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.data.datasource.disk.BaseDiskSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onSubscription
private const val APP_THEME_KEY = "$BASE_KEY:theme"
private const val APP_LANGUAGE_KEY = "$BASE_KEY:appLocale"
private const val DEFAULT_SAVE_OPTION_KEY = "$BASE_KEY:defaultSaveOption"
private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "$BASE_KEY:biometricIntegritySource"
private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "$BASE_KEY:accountBiometricIntegrityValid"
private const val ALERT_THRESHOLD_SECONDS_KEY = "$BASE_KEY:alertThresholdSeconds"
private const val FIRST_LAUNCH_KEY = "$BASE_KEY:hasSeenWelcomeTutorial"
private const val CRASH_LOGGING_ENABLED_KEY = "$BASE_KEY:crashLoggingEnabled"
private const val APP_THEME_KEY = "theme"
private const val APP_LANGUAGE_KEY = "appLocale"
private const val DEFAULT_SAVE_OPTION_KEY = "defaultSaveOption"
private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "biometricIntegritySource"
private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "accountBiometricIntegrityValid"
private const val ALERT_THRESHOLD_SECONDS_KEY = "alertThresholdSeconds"
private const val FIRST_LAUNCH_KEY = "hasSeenWelcomeTutorial"
private const val CRASH_LOGGING_ENABLED_KEY = "crashLoggingEnabled"
private const val SCREEN_CAPTURE_ALLOW_KEY = "screenCaptureAllowed"
private const val HAS_USER_DISMISSED_DOWNLOAD_BITWARDEN_KEY =
"$BASE_KEY:hasUserDismissedDownloadBitwardenCard"
"hasUserDismissedDownloadBitwardenCard"
private const val HAS_USER_DISMISSED_SYNC_WITH_BITWARDEN_KEY =
"$BASE_KEY:hasUserDismissedSyncWithBitwardenCard"
"hasUserDismissedSyncWithBitwardenCard"
private const val PREVIOUSLY_SYNCED_BITWARDEN_ACCOUNT_IDS_KEY =
"$BASE_KEY:previouslySyncedBitwardenAccountIds"
"previouslySyncedBitwardenAccountIds"
private const val DEFAULT_ALERT_THRESHOLD_SECONDS = 7
/**
@ -138,13 +138,13 @@ class SettingsDiskSourceImpl(
.onSubscription { emit(getBoolean(CRASH_LOGGING_ENABLED_KEY)) }
override var hasUserDismissedDownloadBitwardenCard: Boolean?
get() = getBoolean(HAS_USER_DISMISSED_DOWNLOAD_BITWARDEN_KEY, null)
get() = getBoolean(HAS_USER_DISMISSED_DOWNLOAD_BITWARDEN_KEY)
set(value) {
putBoolean(HAS_USER_DISMISSED_DOWNLOAD_BITWARDEN_KEY, value)
}
override var hasUserDismissedSyncWithBitwardenCard: Boolean?
get() = getBoolean(HAS_USER_DISMISSED_SYNC_WITH_BITWARDEN_KEY, null)
get() = getBoolean(HAS_USER_DISMISSED_SYNC_WITH_BITWARDEN_KEY)
set(value) {
putBoolean(HAS_USER_DISMISSED_SYNC_WITH_BITWARDEN_KEY, value)
}
@ -158,8 +158,7 @@ class SettingsDiskSourceImpl(
}
override fun getAlertThresholdSeconds() =
getInt(ALERT_THRESHOLD_SECONDS_KEY, default = DEFAULT_ALERT_THRESHOLD_SECONDS)
?: DEFAULT_ALERT_THRESHOLD_SECONDS
getInt(ALERT_THRESHOLD_SECONDS_KEY) ?: DEFAULT_ALERT_THRESHOLD_SECONDS
override fun getAlertThresholdSecondsFlow(): Flow<Int> = mutableAlertThresholdSecondsFlow
.onSubscription { emit(getAlertThresholdSeconds()) }

View File

@ -21,7 +21,7 @@ class FeatureFlagOverrideDiskSourceTest {
val key = FlagKey.DummyBoolean
assertFalse(
fakeSharedPreferences.getBoolean(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
false,
),
)
@ -29,7 +29,7 @@ class FeatureFlagOverrideDiskSourceTest {
featureFlagOverrideDiskSource.saveFeatureFlag(key, value)
assertTrue(
fakeSharedPreferences.getBoolean(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
false,
),
)
@ -39,7 +39,7 @@ class FeatureFlagOverrideDiskSourceTest {
fun `call to get feature flag should return correct value for booleans`() {
val key = FlagKey.DummyBoolean
fakeSharedPreferences.edit {
putBoolean(key.keyName, true)
putBoolean("$BASE_STORAGE_PREFIX${key.keyName}", true)
}
val actual = featureFlagOverrideDiskSource.getFeatureFlag(key)
@ -51,7 +51,7 @@ class FeatureFlagOverrideDiskSourceTest {
val key = FlagKey.DummyString
assertNull(
fakeSharedPreferences.getString(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
null,
),
)
@ -59,7 +59,7 @@ class FeatureFlagOverrideDiskSourceTest {
featureFlagOverrideDiskSource.saveFeatureFlag(key, expectedValue)
assertEquals(
fakeSharedPreferences.getString(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
null,
),
expectedValue,
@ -72,7 +72,7 @@ class FeatureFlagOverrideDiskSourceTest {
assertNull(featureFlagOverrideDiskSource.getFeatureFlag(key))
val expectedValue = "string"
fakeSharedPreferences.edit {
putString(key.keyName, expectedValue)
putString("$BASE_STORAGE_PREFIX${key.keyName}", expectedValue)
}
val actual = featureFlagOverrideDiskSource.getFeatureFlag(key)
@ -84,7 +84,7 @@ class FeatureFlagOverrideDiskSourceTest {
val key = FlagKey.DummyInt()
assertEquals(
fakeSharedPreferences.getInt(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
0,
),
0,
@ -93,7 +93,7 @@ class FeatureFlagOverrideDiskSourceTest {
featureFlagOverrideDiskSource.saveFeatureFlag(key, expectedValue)
assertEquals(
fakeSharedPreferences.getInt(
key.keyName,
"$BASE_STORAGE_PREFIX${key.keyName}",
0,
),
expectedValue,
@ -106,10 +106,12 @@ class FeatureFlagOverrideDiskSourceTest {
assertNull(featureFlagOverrideDiskSource.getFeatureFlag(key))
val expectedValue = 1
fakeSharedPreferences.edit {
putInt(key.keyName, expectedValue)
putInt("$BASE_STORAGE_PREFIX${key.keyName}", expectedValue)
}
val actual = featureFlagOverrideDiskSource.getFeatureFlag(key)
assertEquals(actual, expectedValue)
}
}
private const val BASE_STORAGE_PREFIX = "bwPreferencesStorage:"

View File

@ -37,4 +37,6 @@ kotlin {
}
}
dependencies { }
dependencies {
implementation(libs.androidx.core.ktx)
}

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.data.platform.datasource.disk
package com.bitwarden.data.datasource.disk
import android.content.SharedPreferences
import androidx.core.content.edit
@ -6,7 +6,7 @@ import androidx.core.content.edit
/**
* Base class for simplifying interactions with [SharedPreferences].
*/
@Suppress("UnnecessaryAbstractClass")
@Suppress("UnnecessaryAbstractClass", "TooManyFunctions")
abstract class BaseDiskSource(
private val sharedPreferences: SharedPreferences,
) {
@ -103,6 +103,18 @@ abstract class BaseDiskSource(
value: String?,
): Unit = sharedPreferences.edit { putString(key.withBase(), value) }
protected fun putStringSet(
key: String,
value: Set<String>?,
): Unit = sharedPreferences.edit {
putStringSet(key.withBase(), value)
}
protected fun getStringSet(
key: String,
default: Set<String>?,
): Set<String>? = sharedPreferences.getStringSet(key.withBase(), default)
protected fun removeWithPrefix(prefix: String) {
sharedPreferences
.all