mirror of
https://github.com/bitwarden/android.git
synced 2025-03-16 19:28:44 +03:00
Add helper methods to disk source (#1311)
This commit is contained in:
parent
12610f83eb
commit
70558499b4
8 changed files with 161 additions and 150 deletions
|
@ -4,9 +4,7 @@ import android.content.SharedPreferences
|
|||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.PendingAuthRequestJson
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseEncryptedDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseEncryptedDiskSource.Companion.ENCRYPTED_BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.legacy.LegacySecureStorageMigrator
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.data.platform.util.decodeFromStringOrNull
|
||||
|
@ -18,28 +16,30 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import java.util.UUID
|
||||
|
||||
private const val ACCOUNT_TOKENS_KEY = "$ENCRYPTED_BASE_KEY:accountTokens"
|
||||
private const val BIOMETRICS_UNLOCK_KEY = "$ENCRYPTED_BASE_KEY:userKeyBiometricUnlock"
|
||||
private const val USER_AUTO_UNLOCK_KEY_KEY = "$ENCRYPTED_BASE_KEY:userKeyAutoUnlock"
|
||||
private const val DEVICE_KEY_KEY = "$ENCRYPTED_BASE_KEY:deviceKey"
|
||||
private const val PENDING_ADMIN_AUTH_REQUEST_KEY = "$ENCRYPTED_BASE_KEY:pendingAdminAuthRequest"
|
||||
// These keys should be encrypted
|
||||
private const val ACCOUNT_TOKENS_KEY = "accountTokens"
|
||||
private const val BIOMETRICS_UNLOCK_KEY = "userKeyBiometricUnlock"
|
||||
private const val USER_AUTO_UNLOCK_KEY_KEY = "userKeyAutoUnlock"
|
||||
private const val DEVICE_KEY_KEY = "deviceKey"
|
||||
private const val PENDING_ADMIN_AUTH_REQUEST_KEY = "pendingAdminAuthRequest"
|
||||
|
||||
private const val UNIQUE_APP_ID_KEY = "$BASE_KEY:appId"
|
||||
private const val REMEMBERED_EMAIL_ADDRESS_KEY = "$BASE_KEY:rememberedEmail"
|
||||
private const val REMEMBERED_ORG_IDENTIFIER_KEY = "$BASE_KEY:rememberedOrgIdentifier"
|
||||
private const val STATE_KEY = "$BASE_KEY:state"
|
||||
private const val LAST_ACTIVE_TIME_KEY = "$BASE_KEY:lastActiveTime"
|
||||
private const val INVALID_UNLOCK_ATTEMPTS_KEY = "$BASE_KEY:invalidUnlockAttempts"
|
||||
private const val MASTER_KEY_ENCRYPTION_USER_KEY = "$BASE_KEY:masterKeyEncryptedUserKey"
|
||||
private const val MASTER_KEY_ENCRYPTION_PRIVATE_KEY = "$BASE_KEY:encPrivateKey"
|
||||
private const val PIN_PROTECTED_USER_KEY_KEY = "$BASE_KEY:pinKeyEncryptedUserKey"
|
||||
private const val ENCRYPTED_PIN_KEY = "$BASE_KEY:protectedPin"
|
||||
private const val ORGANIZATIONS_KEY = "$BASE_KEY:organizations"
|
||||
private const val ORGANIZATION_KEYS_KEY = "$BASE_KEY:encOrgKeys"
|
||||
private const val TWO_FACTOR_TOKEN_KEY = "$BASE_KEY:twoFactorToken"
|
||||
private const val MASTER_PASSWORD_HASH_KEY = "$BASE_KEY:keyHash"
|
||||
private const val POLICIES_KEY = "$BASE_KEY:policies"
|
||||
private const val SHOULD_TRUST_DEVICE_KEY = "$BASE_KEY:shouldTrustDevice"
|
||||
// These keys should not be encrypted
|
||||
private const val UNIQUE_APP_ID_KEY = "appId"
|
||||
private const val REMEMBERED_EMAIL_ADDRESS_KEY = "rememberedEmail"
|
||||
private const val REMEMBERED_ORG_IDENTIFIER_KEY = "rememberedOrgIdentifier"
|
||||
private const val STATE_KEY = "state"
|
||||
private const val LAST_ACTIVE_TIME_KEY = "lastActiveTime"
|
||||
private const val INVALID_UNLOCK_ATTEMPTS_KEY = "invalidUnlockAttempts"
|
||||
private const val MASTER_KEY_ENCRYPTION_USER_KEY = "masterKeyEncryptedUserKey"
|
||||
private const val MASTER_KEY_ENCRYPTION_PRIVATE_KEY = "encPrivateKey"
|
||||
private const val PIN_PROTECTED_USER_KEY_KEY = "pinKeyEncryptedUserKey"
|
||||
private const val ENCRYPTED_PIN_KEY = "protectedPin"
|
||||
private const val ORGANIZATIONS_KEY = "organizations"
|
||||
private const val ORGANIZATION_KEYS_KEY = "encOrgKeys"
|
||||
private const val TWO_FACTOR_TOKEN_KEY = "twoFactorToken"
|
||||
private const val MASTER_PASSWORD_HASH_KEY = "keyHash"
|
||||
private const val POLICIES_KEY = "policies"
|
||||
private const val SHOULD_TRUST_DEVICE_KEY = "shouldTrustDevice"
|
||||
|
||||
/**
|
||||
* Primary implementation of [AuthDiskSource].
|
||||
|
@ -130,61 +130,63 @@ class AuthDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getShouldTrustDevice(userId: String): Boolean =
|
||||
requireNotNull(getBoolean(key = "${SHOULD_TRUST_DEVICE_KEY}_$userId", default = false))
|
||||
requireNotNull(
|
||||
getBoolean(key = SHOULD_TRUST_DEVICE_KEY.appendIdentifier(userId), default = false),
|
||||
)
|
||||
|
||||
override fun storeShouldTrustDevice(userId: String, shouldTrustDevice: Boolean?) {
|
||||
putBoolean("${SHOULD_TRUST_DEVICE_KEY}_$userId", shouldTrustDevice)
|
||||
putBoolean(SHOULD_TRUST_DEVICE_KEY.appendIdentifier(userId), shouldTrustDevice)
|
||||
}
|
||||
|
||||
override fun getLastActiveTimeMillis(userId: String): Long? =
|
||||
getLong(key = "${LAST_ACTIVE_TIME_KEY}_$userId")
|
||||
getLong(key = LAST_ACTIVE_TIME_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeLastActiveTimeMillis(
|
||||
userId: String,
|
||||
lastActiveTimeMillis: Long?,
|
||||
) {
|
||||
putLong(
|
||||
key = "${LAST_ACTIVE_TIME_KEY}_$userId",
|
||||
key = LAST_ACTIVE_TIME_KEY.appendIdentifier(userId),
|
||||
value = lastActiveTimeMillis,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getInvalidUnlockAttempts(userId: String): Int? =
|
||||
getInt(key = "${INVALID_UNLOCK_ATTEMPTS_KEY}_$userId")
|
||||
getInt(key = INVALID_UNLOCK_ATTEMPTS_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeInvalidUnlockAttempts(
|
||||
userId: String,
|
||||
invalidUnlockAttempts: Int?,
|
||||
) {
|
||||
putInt(
|
||||
key = "${INVALID_UNLOCK_ATTEMPTS_KEY}_$userId",
|
||||
key = INVALID_UNLOCK_ATTEMPTS_KEY.appendIdentifier(userId),
|
||||
value = invalidUnlockAttempts,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUserKey(userId: String): String? =
|
||||
getString(key = "${MASTER_KEY_ENCRYPTION_USER_KEY}_$userId")
|
||||
getString(key = MASTER_KEY_ENCRYPTION_USER_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeUserKey(userId: String, userKey: String?) {
|
||||
putString(
|
||||
key = "${MASTER_KEY_ENCRYPTION_USER_KEY}_$userId",
|
||||
key = MASTER_KEY_ENCRYPTION_USER_KEY.appendIdentifier(userId),
|
||||
value = userKey,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPrivateKey(userId: String): String? =
|
||||
getString(key = "${MASTER_KEY_ENCRYPTION_PRIVATE_KEY}_$userId")
|
||||
getString(key = MASTER_KEY_ENCRYPTION_PRIVATE_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storePrivateKey(userId: String, privateKey: String?) {
|
||||
putString(
|
||||
key = "${MASTER_KEY_ENCRYPTION_PRIVATE_KEY}_$userId",
|
||||
key = MASTER_KEY_ENCRYPTION_PRIVATE_KEY.appendIdentifier(userId),
|
||||
value = privateKey,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUserAutoUnlockKey(userId: String): String? =
|
||||
getEncryptedString(
|
||||
key = "${USER_AUTO_UNLOCK_KEY_KEY}_$userId",
|
||||
key = USER_AUTO_UNLOCK_KEY_KEY.appendIdentifier(userId),
|
||||
default = null,
|
||||
)
|
||||
|
||||
|
@ -193,26 +195,26 @@ class AuthDiskSourceImpl(
|
|||
userAutoUnlockKey: String?,
|
||||
) {
|
||||
putEncryptedString(
|
||||
key = "${USER_AUTO_UNLOCK_KEY_KEY}_$userId",
|
||||
key = USER_AUTO_UNLOCK_KEY_KEY.appendIdentifier(userId),
|
||||
value = userAutoUnlockKey,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getDeviceKey(
|
||||
userId: String,
|
||||
): String? = getEncryptedString(key = "${DEVICE_KEY_KEY}_$userId")
|
||||
): String? = getEncryptedString(key = DEVICE_KEY_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeDeviceKey(
|
||||
userId: String,
|
||||
deviceKey: String?,
|
||||
) {
|
||||
putEncryptedString(key = "${DEVICE_KEY_KEY}_$userId", value = deviceKey)
|
||||
putEncryptedString(key = DEVICE_KEY_KEY.appendIdentifier(userId), value = deviceKey)
|
||||
}
|
||||
|
||||
override fun getPendingAuthRequest(
|
||||
userId: String,
|
||||
): PendingAuthRequestJson? =
|
||||
getEncryptedString(key = "${PENDING_ADMIN_AUTH_REQUEST_KEY}_$userId")
|
||||
getEncryptedString(key = PENDING_ADMIN_AUTH_REQUEST_KEY.appendIdentifier(userId))
|
||||
?.let { json.decodeFromStringOrNull(it) }
|
||||
|
||||
override fun storePendingAuthRequest(
|
||||
|
@ -220,27 +222,27 @@ class AuthDiskSourceImpl(
|
|||
pendingAuthRequest: PendingAuthRequestJson?,
|
||||
) {
|
||||
putEncryptedString(
|
||||
key = "${PENDING_ADMIN_AUTH_REQUEST_KEY}_$userId",
|
||||
key = PENDING_ADMIN_AUTH_REQUEST_KEY.appendIdentifier(userId),
|
||||
value = pendingAuthRequest?.let { json.encodeToString(it) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUserBiometricUnlockKey(userId: String): String? =
|
||||
getEncryptedString(key = "${BIOMETRICS_UNLOCK_KEY}_$userId")
|
||||
getEncryptedString(key = BIOMETRICS_UNLOCK_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeUserBiometricUnlockKey(
|
||||
userId: String,
|
||||
biometricsKey: String?,
|
||||
) {
|
||||
putEncryptedString(
|
||||
key = "${BIOMETRICS_UNLOCK_KEY}_$userId",
|
||||
key = BIOMETRICS_UNLOCK_KEY.appendIdentifier(userId),
|
||||
value = biometricsKey,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPinProtectedUserKey(userId: String): String? =
|
||||
inMemoryPinProtectedUserKeys[userId]
|
||||
?: getString(key = "${PIN_PROTECTED_USER_KEY_KEY}_$userId")
|
||||
?: getString(key = PIN_PROTECTED_USER_KEY_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storePinProtectedUserKey(
|
||||
userId: String,
|
||||
|
@ -250,36 +252,36 @@ class AuthDiskSourceImpl(
|
|||
inMemoryPinProtectedUserKeys[userId] = pinProtectedUserKey
|
||||
if (inMemoryOnly) return
|
||||
putString(
|
||||
key = "${PIN_PROTECTED_USER_KEY_KEY}_$userId",
|
||||
key = PIN_PROTECTED_USER_KEY_KEY.appendIdentifier(userId),
|
||||
value = pinProtectedUserKey,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTwoFactorToken(email: String): String? =
|
||||
getString(key = "${TWO_FACTOR_TOKEN_KEY}_$email")
|
||||
getString(key = TWO_FACTOR_TOKEN_KEY.appendIdentifier(email))
|
||||
|
||||
override fun storeTwoFactorToken(email: String, twoFactorToken: String?) {
|
||||
putString(
|
||||
key = "${TWO_FACTOR_TOKEN_KEY}_$email",
|
||||
key = TWO_FACTOR_TOKEN_KEY.appendIdentifier(email),
|
||||
value = twoFactorToken,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getEncryptedPin(userId: String): String? =
|
||||
getString(key = "${ENCRYPTED_PIN_KEY}_$userId")
|
||||
getString(key = ENCRYPTED_PIN_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeEncryptedPin(
|
||||
userId: String,
|
||||
encryptedPin: String?,
|
||||
) {
|
||||
putString(
|
||||
key = "${ENCRYPTED_PIN_KEY}_$userId",
|
||||
key = ENCRYPTED_PIN_KEY.appendIdentifier(userId),
|
||||
value = encryptedPin,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOrganizationKeys(userId: String): Map<String, String>? =
|
||||
getString(key = "${ORGANIZATION_KEYS_KEY}_$userId")
|
||||
getString(key = ORGANIZATION_KEYS_KEY.appendIdentifier(userId))
|
||||
?.let { json.decodeFromStringOrNull(it) }
|
||||
|
||||
override fun storeOrganizationKeys(
|
||||
|
@ -287,7 +289,7 @@ class AuthDiskSourceImpl(
|
|||
organizationKeys: Map<String, String>?,
|
||||
) {
|
||||
putString(
|
||||
key = "${ORGANIZATION_KEYS_KEY}_$userId",
|
||||
key = ORGANIZATION_KEYS_KEY.appendIdentifier(userId),
|
||||
value = organizationKeys?.let { json.encodeToString(it) },
|
||||
)
|
||||
}
|
||||
|
@ -295,7 +297,7 @@ class AuthDiskSourceImpl(
|
|||
override fun getOrganizations(
|
||||
userId: String,
|
||||
): List<SyncResponseJson.Profile.Organization>? =
|
||||
getString(key = "${ORGANIZATIONS_KEY}_$userId")
|
||||
getString(key = ORGANIZATIONS_KEY.appendIdentifier(userId))
|
||||
?.let {
|
||||
// The organizations are stored as a map
|
||||
val organizationMap: Map<String, SyncResponseJson.Profile.Organization>? =
|
||||
|
@ -314,7 +316,7 @@ class AuthDiskSourceImpl(
|
|||
organizations: List<SyncResponseJson.Profile.Organization>?,
|
||||
) {
|
||||
putString(
|
||||
key = "${ORGANIZATIONS_KEY}_$userId",
|
||||
key = ORGANIZATIONS_KEY.appendIdentifier(userId),
|
||||
value = organizations?.let { nonNullOrganizations ->
|
||||
// The organizations are stored as a map
|
||||
val organizationsMap = nonNullOrganizations.associateBy { it.id }
|
||||
|
@ -325,14 +327,14 @@ class AuthDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getMasterPasswordHash(userId: String): String? =
|
||||
getString(key = "${MASTER_PASSWORD_HASH_KEY}_$userId")
|
||||
getString(key = MASTER_PASSWORD_HASH_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeMasterPasswordHash(userId: String, passwordHash: String?) {
|
||||
putString(key = "${MASTER_PASSWORD_HASH_KEY}_$userId", value = passwordHash)
|
||||
putString(key = MASTER_PASSWORD_HASH_KEY.appendIdentifier(userId), value = passwordHash)
|
||||
}
|
||||
|
||||
override fun getPolicies(userId: String): List<SyncResponseJson.Policy>? =
|
||||
getString(key = "${POLICIES_KEY}_$userId")
|
||||
getString(key = POLICIES_KEY.appendIdentifier(userId))
|
||||
?.let {
|
||||
// The policies are stored as a map.
|
||||
val policiesMap: Map<String, SyncResponseJson.Policy>? =
|
||||
|
@ -348,7 +350,7 @@ class AuthDiskSourceImpl(
|
|||
|
||||
override fun storePolicies(userId: String, policies: List<SyncResponseJson.Policy>?) {
|
||||
putString(
|
||||
key = "${POLICIES_KEY}_$userId",
|
||||
key = POLICIES_KEY.appendIdentifier(userId),
|
||||
value = policies?.let { nonNullPolicies ->
|
||||
// The policies are stored as a map.
|
||||
val policiesMap = nonNullPolicies.associateBy { it.id }
|
||||
|
@ -359,7 +361,7 @@ class AuthDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getAccountTokens(userId: String): AccountTokensJson? =
|
||||
getEncryptedString(key = "${ACCOUNT_TOKENS_KEY}_$userId")
|
||||
getEncryptedString(key = ACCOUNT_TOKENS_KEY.appendIdentifier(userId))
|
||||
?.let { json.decodeFromStringOrNull(it) }
|
||||
|
||||
override fun getAccountTokensFlow(userId: String): Flow<AccountTokensJson?> =
|
||||
|
@ -368,7 +370,7 @@ class AuthDiskSourceImpl(
|
|||
|
||||
override fun storeAccountTokens(userId: String, accountTokens: AccountTokensJson?) {
|
||||
putEncryptedString(
|
||||
key = "${ACCOUNT_TOKENS_KEY}_$userId",
|
||||
key = ACCOUNT_TOKENS_KEY.appendIdentifier(userId),
|
||||
value = accountTokens?.let { json.encodeToString(it) },
|
||||
)
|
||||
getMutableAccountTokensFlow(userId = userId).tryEmit(accountTokens)
|
||||
|
|
|
@ -18,8 +18,8 @@ abstract class BaseDiskSource(
|
|||
key: String,
|
||||
default: Boolean? = null,
|
||||
): Boolean? =
|
||||
if (sharedPreferences.contains(key)) {
|
||||
sharedPreferences.getBoolean(key, false)
|
||||
if (sharedPreferences.contains(key.withBase())) {
|
||||
sharedPreferences.getBoolean(key.withBase(), false)
|
||||
} else {
|
||||
// Make sure we can return a null value as a default if necessary
|
||||
default
|
||||
|
@ -35,9 +35,9 @@ abstract class BaseDiskSource(
|
|||
): Unit =
|
||||
sharedPreferences.edit {
|
||||
if (value != null) {
|
||||
putBoolean(key, value)
|
||||
putBoolean(key.withBase(), value)
|
||||
} else {
|
||||
remove(key)
|
||||
remove(key.withBase())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,8 @@ abstract class BaseDiskSource(
|
|||
key: String,
|
||||
default: Int? = null,
|
||||
): Int? =
|
||||
if (sharedPreferences.contains(key)) {
|
||||
sharedPreferences.getInt(key, 0)
|
||||
if (sharedPreferences.contains(key.withBase())) {
|
||||
sharedPreferences.getInt(key.withBase(), 0)
|
||||
} else {
|
||||
// Make sure we can return a null value as a default if necessary
|
||||
default
|
||||
|
@ -66,9 +66,9 @@ abstract class BaseDiskSource(
|
|||
): Unit =
|
||||
sharedPreferences.edit {
|
||||
if (value != null) {
|
||||
putInt(key, value)
|
||||
putInt(key.withBase(), value)
|
||||
} else {
|
||||
remove(key)
|
||||
remove(key.withBase())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,8 @@ abstract class BaseDiskSource(
|
|||
key: String,
|
||||
default: Long? = null,
|
||||
): Long? =
|
||||
if (sharedPreferences.contains(key)) {
|
||||
sharedPreferences.getLong(key, 0)
|
||||
if (sharedPreferences.contains(key.withBase())) {
|
||||
sharedPreferences.getLong(key.withBase(), 0)
|
||||
} else {
|
||||
// Make sure we can return a null value as a default if necessary
|
||||
default
|
||||
|
@ -97,31 +97,34 @@ abstract class BaseDiskSource(
|
|||
): Unit =
|
||||
sharedPreferences.edit {
|
||||
if (value != null) {
|
||||
putLong(key, value)
|
||||
putLong(key.withBase(), value)
|
||||
} else {
|
||||
remove(key)
|
||||
remove(key.withBase())
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getString(
|
||||
key: String,
|
||||
default: String? = null,
|
||||
): String? = sharedPreferences.getString(key, default)
|
||||
): String? = sharedPreferences.getString(key.withBase(), default)
|
||||
|
||||
protected fun putString(
|
||||
key: String,
|
||||
value: String?,
|
||||
): Unit = sharedPreferences.edit { putString(key, value) }
|
||||
): Unit = sharedPreferences.edit { putString(key.withBase(), value) }
|
||||
|
||||
protected fun removeWithPrefix(prefix: String) {
|
||||
sharedPreferences
|
||||
.all
|
||||
.keys
|
||||
.filter { it.startsWith(prefix) }
|
||||
.filter { it.startsWith(prefix.withBase()) }
|
||||
.forEach { sharedPreferences.edit { remove(it) } }
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BASE_KEY: String = "bwPreferencesStorage"
|
||||
}
|
||||
protected fun String.appendIdentifier(identifier: String): String = "${this}_$identifier"
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for prepending the key with the appropriate base storage key.
|
||||
*/
|
||||
private fun String.withBase(): String = "bwPreferencesStorage:$this"
|
||||
|
|
|
@ -18,14 +18,15 @@ abstract class BaseEncryptedDiskSource(
|
|||
protected fun getEncryptedString(
|
||||
key: String,
|
||||
default: String? = null,
|
||||
): String? = encryptedSharedPreferences.getString(key, default)
|
||||
): String? = encryptedSharedPreferences.getString(key.withBase(), default)
|
||||
|
||||
protected fun putEncryptedString(
|
||||
key: String,
|
||||
value: String?,
|
||||
): Unit = encryptedSharedPreferences.edit { putString(key, value) }
|
||||
|
||||
companion object {
|
||||
const val ENCRYPTED_BASE_KEY: String = "bwSecureStorage"
|
||||
}
|
||||
): Unit = encryptedSharedPreferences.edit { putString(key.withBase(), value) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for prepending the key with the appropriate base storage key.
|
||||
*/
|
||||
private fun String.withBase(): String = "bwSecureStorage:$this"
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.platform.datasource.disk
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.data.platform.util.decodeFromStringOrNull
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -10,7 +9,7 @@ import kotlinx.coroutines.flow.onSubscription
|
|||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private const val PRE_AUTH_URLS_KEY = "$BASE_KEY:preAuthEnvironmentUrls"
|
||||
private const val PRE_AUTH_URLS_KEY = "preAuthEnvironmentUrls"
|
||||
|
||||
/**
|
||||
* Primary implementation of [EnvironmentDiskSource].
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package com.x8bit.bitwarden.data.platform.datasource.disk
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.util.getBinaryLongFromZoneDateTime
|
||||
import com.x8bit.bitwarden.data.platform.util.getZoneDateTimeFromBinaryLong
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
private const val CURRENT_PUSH_TOKEN_KEY = "${BASE_KEY}:pushCurrentToken"
|
||||
private const val LAST_REGISTRATION_DATE_KEY = "${BASE_KEY}:pushLastRegistrationDate"
|
||||
private const val REGISTERED_PUSH_TOKEN_KEY = "${BASE_KEY}:pushRegisteredToken"
|
||||
private const val CURRENT_PUSH_TOKEN_KEY = "pushCurrentToken"
|
||||
private const val LAST_REGISTRATION_DATE_KEY = "pushLastRegistrationDate"
|
||||
private const val REGISTERED_PUSH_TOKEN_KEY = "pushRegisteredToken"
|
||||
|
||||
/**
|
||||
* Primary implementation of [PushDiskSource].
|
||||
|
@ -32,17 +31,17 @@ class PushDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getCurrentPushToken(userId: String): String? {
|
||||
return getString("${CURRENT_PUSH_TOKEN_KEY}_$userId")
|
||||
return getString(CURRENT_PUSH_TOKEN_KEY.appendIdentifier(userId))
|
||||
}
|
||||
|
||||
override fun getLastPushTokenRegistrationDate(userId: String): ZonedDateTime? {
|
||||
return getLong("${LAST_REGISTRATION_DATE_KEY}_$userId", null)
|
||||
return getLong(LAST_REGISTRATION_DATE_KEY.appendIdentifier(userId), null)
|
||||
?.let { getZoneDateTimeFromBinaryLong(it) }
|
||||
}
|
||||
|
||||
override fun storeCurrentPushToken(userId: String, pushToken: String?) {
|
||||
putString(
|
||||
key = "${CURRENT_PUSH_TOKEN_KEY}_$userId",
|
||||
key = CURRENT_PUSH_TOKEN_KEY.appendIdentifier(userId),
|
||||
value = pushToken,
|
||||
)
|
||||
}
|
||||
|
@ -52,7 +51,7 @@ class PushDiskSourceImpl(
|
|||
registrationDate: ZonedDateTime?,
|
||||
) {
|
||||
putLong(
|
||||
key = "${LAST_REGISTRATION_DATE_KEY}_$userId",
|
||||
key = LAST_REGISTRATION_DATE_KEY.appendIdentifier(userId),
|
||||
value = registrationDate?.let { getBinaryLongFromZoneDateTime(registrationDate) },
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.platform.datasource.disk
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseDiskSource.Companion.BASE_KEY
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
|
@ -15,25 +14,25 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import java.time.Instant
|
||||
|
||||
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_LAST_SYNC_TIME = "$BASE_KEY:vaultLastSyncTime"
|
||||
private const val VAULT_TIMEOUT_ACTION_KEY = "$BASE_KEY:vaultTimeoutAction"
|
||||
private const val VAULT_TIME_IN_MINUTES_KEY = "$BASE_KEY:vaultTimeout"
|
||||
private const val DEFAULT_URI_MATCH_TYPE_KEY = "$BASE_KEY:defaultUriMatch"
|
||||
private const val DISABLE_AUTO_TOTP_COPY_KEY = "$BASE_KEY:disableAutoTotpCopy"
|
||||
private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "$BASE_KEY:autofillDisableSavePrompt"
|
||||
private const val DISABLE_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon"
|
||||
private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "$BASE_KEY:approvePasswordlessLogins"
|
||||
private const val SCREEN_CAPTURE_ALLOW_KEY = "$BASE_KEY:screenCaptureAllowed"
|
||||
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 CRASH_LOGGING_ENABLED_KEY = "$BASE_KEY:crashLoggingEnabled"
|
||||
private const val CLEAR_CLIPBOARD_INTERVAL_KEY = "$BASE_KEY:clearClipboard"
|
||||
private const val INITIAL_AUTOFILL_DIALOG_SHOWN = "$BASE_KEY:addSitePromptShown"
|
||||
private const val APP_LANGUAGE_KEY = "appLocale"
|
||||
private const val APP_THEME_KEY = "theme"
|
||||
private const val PULL_TO_REFRESH_KEY = "syncOnRefresh"
|
||||
private const val INLINE_AUTOFILL_ENABLED_KEY = "inlineAutofillEnabled"
|
||||
private const val BLOCKED_AUTOFILL_URIS_KEY = "autofillBlacklistedUris"
|
||||
private const val VAULT_LAST_SYNC_TIME = "vaultLastSyncTime"
|
||||
private const val VAULT_TIMEOUT_ACTION_KEY = "vaultTimeoutAction"
|
||||
private const val VAULT_TIME_IN_MINUTES_KEY = "vaultTimeout"
|
||||
private const val DEFAULT_URI_MATCH_TYPE_KEY = "defaultUriMatch"
|
||||
private const val DISABLE_AUTO_TOTP_COPY_KEY = "disableAutoTotpCopy"
|
||||
private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "autofillDisableSavePrompt"
|
||||
private const val DISABLE_ICON_LOADING_KEY = "disableFavicon"
|
||||
private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "approvePasswordlessLogins"
|
||||
private const val SCREEN_CAPTURE_ALLOW_KEY = "screenCaptureAllowed"
|
||||
private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "biometricIntegritySource"
|
||||
private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "accountBiometricIntegrityValid"
|
||||
private const val CRASH_LOGGING_ENABLED_KEY = "crashLoggingEnabled"
|
||||
private const val CLEAR_CLIPBOARD_INTERVAL_KEY = "clearClipboard"
|
||||
private const val INITIAL_AUTOFILL_DIALOG_SHOWN = "addSitePromptShown"
|
||||
|
||||
/**
|
||||
* Primary implementation of [SettingsDiskSource].
|
||||
|
@ -44,8 +43,7 @@ class SettingsDiskSourceImpl(
|
|||
private val json: Json,
|
||||
) : BaseDiskSource(sharedPreferences = sharedPreferences),
|
||||
SettingsDiskSource {
|
||||
private val mutableAppThemeFlow =
|
||||
bufferedMutableSharedFlow<AppTheme>(replay = 1)
|
||||
private val mutableAppThemeFlow = bufferedMutableSharedFlow<AppTheme>(replay = 1)
|
||||
|
||||
private val mutableLastSyncFlowMap = mutableMapOf<String, MutableSharedFlow<Instant?>>()
|
||||
|
||||
|
@ -58,11 +56,9 @@ class SettingsDiskSourceImpl(
|
|||
private val mutablePullToRefreshEnabledFlowMap =
|
||||
mutableMapOf<String, MutableSharedFlow<Boolean?>>()
|
||||
|
||||
private val mutableIsIconLoadingDisabledFlow =
|
||||
bufferedMutableSharedFlow<Boolean?>()
|
||||
private val mutableIsIconLoadingDisabledFlow = bufferedMutableSharedFlow<Boolean?>()
|
||||
|
||||
private val mutableIsCrashLoggingEnabledFlow =
|
||||
bufferedMutableSharedFlow<Boolean?>()
|
||||
private val mutableIsCrashLoggingEnabledFlow = bufferedMutableSharedFlow<Boolean?>()
|
||||
|
||||
private val mutableScreenCaptureAllowedFlowMap =
|
||||
mutableMapOf<String, MutableSharedFlow<Boolean?>>()
|
||||
|
@ -149,7 +145,7 @@ class SettingsDiskSourceImpl(
|
|||
)
|
||||
storeLastSyncTime(userId = userId, lastSyncTime = null)
|
||||
storeClearClipboardFrequencySeconds(userId = userId, frequency = null)
|
||||
removeWithPrefix(prefix = "${ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY}_$userId")
|
||||
removeWithPrefix(prefix = ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY.appendIdentifier(userId))
|
||||
|
||||
// The following are intentionally not cleared so they can be
|
||||
// restored after logging out and back in:
|
||||
|
@ -161,7 +157,9 @@ class SettingsDiskSourceImpl(
|
|||
systemBioIntegrityState: String,
|
||||
): Boolean? =
|
||||
getBoolean(
|
||||
key = "${ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY}_${userId}_$systemBioIntegrityState",
|
||||
key = ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY
|
||||
.appendIdentifier(userId)
|
||||
.appendIdentifier(systemBioIntegrityState),
|
||||
)
|
||||
|
||||
override fun storeAccountBiometricIntegrityValidity(
|
||||
|
@ -170,30 +168,33 @@ class SettingsDiskSourceImpl(
|
|||
value: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY}_${userId}_$systemBioIntegrityState",
|
||||
key = ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY
|
||||
.appendIdentifier(userId)
|
||||
.appendIdentifier(systemBioIntegrityState),
|
||||
value = value,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getAutoCopyTotpDisabled(userId: String): Boolean? =
|
||||
getBoolean(key = "${DISABLE_AUTO_TOTP_COPY_KEY}_$userId")
|
||||
getBoolean(key = DISABLE_AUTO_TOTP_COPY_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeAutoCopyTotpDisabled(
|
||||
userId: String,
|
||||
isAutomaticallyCopyTotpDisabled: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${DISABLE_AUTO_TOTP_COPY_KEY}_$userId",
|
||||
key = DISABLE_AUTO_TOTP_COPY_KEY.appendIdentifier(userId),
|
||||
value = isAutomaticallyCopyTotpDisabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getLastSyncTime(userId: String): Instant? =
|
||||
getLong(key = "${VAULT_LAST_SYNC_TIME}_$userId")?.let { Instant.ofEpochMilli(it) }
|
||||
getLong(key = VAULT_LAST_SYNC_TIME.appendIdentifier(userId))
|
||||
?.let { Instant.ofEpochMilli(it) }
|
||||
|
||||
override fun storeLastSyncTime(userId: String, lastSyncTime: Instant?) {
|
||||
putLong(
|
||||
key = "${VAULT_LAST_SYNC_TIME}_$userId",
|
||||
key = VAULT_LAST_SYNC_TIME.appendIdentifier(userId),
|
||||
value = lastSyncTime?.toEpochMilli(),
|
||||
)
|
||||
getMutableLastSyncFlow(userId = userId).tryEmit(lastSyncTime)
|
||||
|
@ -204,7 +205,7 @@ class SettingsDiskSourceImpl(
|
|||
.onSubscription { emit(getLastSyncTime(userId = userId)) }
|
||||
|
||||
override fun getVaultTimeoutInMinutes(userId: String): Int? =
|
||||
getInt(key = "${VAULT_TIME_IN_MINUTES_KEY}_$userId")
|
||||
getInt(key = VAULT_TIME_IN_MINUTES_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun getVaultTimeoutInMinutesFlow(userId: String): Flow<Int?> =
|
||||
getMutableVaultTimeoutInMinutesFlow(userId = userId)
|
||||
|
@ -215,24 +216,24 @@ class SettingsDiskSourceImpl(
|
|||
vaultTimeoutInMinutes: Int?,
|
||||
) {
|
||||
putInt(
|
||||
key = "${VAULT_TIME_IN_MINUTES_KEY}_$userId",
|
||||
key = VAULT_TIME_IN_MINUTES_KEY.appendIdentifier(userId),
|
||||
value = vaultTimeoutInMinutes,
|
||||
)
|
||||
getMutableVaultTimeoutInMinutesFlow(userId = userId).tryEmit(vaultTimeoutInMinutes)
|
||||
}
|
||||
|
||||
override fun getClearClipboardFrequencySeconds(userId: String): Int? =
|
||||
getInt(key = "${CLEAR_CLIPBOARD_INTERVAL_KEY}_$userId")
|
||||
getInt(key = CLEAR_CLIPBOARD_INTERVAL_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeClearClipboardFrequencySeconds(userId: String, frequency: Int?) {
|
||||
putInt(
|
||||
key = "${CLEAR_CLIPBOARD_INTERVAL_KEY}_$userId",
|
||||
key = CLEAR_CLIPBOARD_INTERVAL_KEY.appendIdentifier(userId),
|
||||
value = frequency,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getVaultTimeoutAction(userId: String): VaultTimeoutAction? =
|
||||
getString(key = "${VAULT_TIMEOUT_ACTION_KEY}_$userId")?.let { storedValue ->
|
||||
getString(key = VAULT_TIMEOUT_ACTION_KEY.appendIdentifier(userId))?.let { storedValue ->
|
||||
VaultTimeoutAction.entries.firstOrNull { storedValue == it.value }
|
||||
}
|
||||
|
||||
|
@ -245,14 +246,14 @@ class SettingsDiskSourceImpl(
|
|||
vaultTimeoutAction: VaultTimeoutAction?,
|
||||
) {
|
||||
putString(
|
||||
key = "${VAULT_TIMEOUT_ACTION_KEY}_$userId",
|
||||
key = VAULT_TIMEOUT_ACTION_KEY.appendIdentifier(userId),
|
||||
value = vaultTimeoutAction?.value,
|
||||
)
|
||||
getMutableVaultTimeoutActionFlow(userId = userId).tryEmit(vaultTimeoutAction)
|
||||
}
|
||||
|
||||
override fun getDefaultUriMatchType(userId: String): UriMatchType? =
|
||||
getInt(key = "${DEFAULT_URI_MATCH_TYPE_KEY}_$userId")?.let { storedValue ->
|
||||
getInt(key = DEFAULT_URI_MATCH_TYPE_KEY.appendIdentifier(userId))?.let { storedValue ->
|
||||
UriMatchType.entries.find { it.value == storedValue }
|
||||
}
|
||||
|
||||
|
@ -261,51 +262,54 @@ class SettingsDiskSourceImpl(
|
|||
uriMatchType: UriMatchType?,
|
||||
) {
|
||||
putInt(
|
||||
key = "${DEFAULT_URI_MATCH_TYPE_KEY}_$userId",
|
||||
key = DEFAULT_URI_MATCH_TYPE_KEY.appendIdentifier(userId),
|
||||
value = uriMatchType?.value,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getAutofillSavePromptDisabled(userId: String): Boolean? =
|
||||
getBoolean(key = "${DISABLE_AUTOFILL_SAVE_PROMPT_KEY}_$userId")
|
||||
getBoolean(key = DISABLE_AUTOFILL_SAVE_PROMPT_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeAutofillSavePromptDisabled(
|
||||
userId: String,
|
||||
isAutofillSavePromptDisabled: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${DISABLE_AUTOFILL_SAVE_PROMPT_KEY}_$userId",
|
||||
key = DISABLE_AUTOFILL_SAVE_PROMPT_KEY.appendIdentifier(userId),
|
||||
value = isAutofillSavePromptDisabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPullToRefreshEnabled(userId: String): Boolean? =
|
||||
getBoolean(key = "${PULL_TO_REFRESH_KEY}_$userId")
|
||||
getBoolean(key = PULL_TO_REFRESH_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun getPullToRefreshEnabledFlow(userId: String): Flow<Boolean?> =
|
||||
getMutablePullToRefreshEnabledFlowMap(userId = userId)
|
||||
.onSubscription { emit(getPullToRefreshEnabled(userId = userId)) }
|
||||
|
||||
override fun storePullToRefreshEnabled(userId: String, isPullToRefreshEnabled: Boolean?) {
|
||||
putBoolean(key = "${PULL_TO_REFRESH_KEY}_$userId", value = isPullToRefreshEnabled)
|
||||
putBoolean(
|
||||
key = PULL_TO_REFRESH_KEY.appendIdentifier(userId),
|
||||
value = isPullToRefreshEnabled,
|
||||
)
|
||||
getMutablePullToRefreshEnabledFlowMap(userId = userId).tryEmit(isPullToRefreshEnabled)
|
||||
}
|
||||
|
||||
override fun getInlineAutofillEnabled(userId: String): Boolean? =
|
||||
getBoolean(key = "${INLINE_AUTOFILL_ENABLED_KEY}_$userId")
|
||||
getBoolean(key = INLINE_AUTOFILL_ENABLED_KEY.appendIdentifier(userId))
|
||||
|
||||
override fun storeInlineAutofillEnabled(
|
||||
userId: String,
|
||||
isInlineAutofillEnabled: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${INLINE_AUTOFILL_ENABLED_KEY}_$userId",
|
||||
key = INLINE_AUTOFILL_ENABLED_KEY.appendIdentifier(userId),
|
||||
value = isInlineAutofillEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getBlockedAutofillUris(userId: String): List<String>? =
|
||||
getString(key = "${BLOCKED_AUTOFILL_URIS_KEY}_$userId")?.let {
|
||||
getString(key = BLOCKED_AUTOFILL_URIS_KEY.appendIdentifier(userId))?.let {
|
||||
json.decodeFromStringOrNull(it)
|
||||
}
|
||||
|
||||
|
@ -314,7 +318,7 @@ class SettingsDiskSourceImpl(
|
|||
blockedAutofillUris: List<String>?,
|
||||
) {
|
||||
putString(
|
||||
key = "${BLOCKED_AUTOFILL_URIS_KEY}_$userId",
|
||||
key = BLOCKED_AUTOFILL_URIS_KEY.appendIdentifier(userId),
|
||||
value = blockedAutofillUris?.let { json.encodeToString(it) },
|
||||
)
|
||||
}
|
||||
|
@ -353,7 +357,7 @@ class SettingsDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean? {
|
||||
return getBoolean(key = "${APPROVE_PASSWORDLESS_LOGINS_KEY}_$userId")
|
||||
return getBoolean(key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId))
|
||||
}
|
||||
|
||||
override fun storeApprovePasswordlessLoginsEnabled(
|
||||
|
@ -361,13 +365,13 @@ class SettingsDiskSourceImpl(
|
|||
isApprovePasswordlessLoginsEnabled: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${APPROVE_PASSWORDLESS_LOGINS_KEY}_$userId",
|
||||
key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId),
|
||||
value = isApprovePasswordlessLoginsEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getScreenCaptureAllowed(userId: String): Boolean? {
|
||||
return getBoolean(key = "${SCREEN_CAPTURE_ALLOW_KEY}_$userId")
|
||||
return getBoolean(key = SCREEN_CAPTURE_ALLOW_KEY.appendIdentifier(userId))
|
||||
}
|
||||
|
||||
override fun getScreenCaptureAllowedFlow(userId: String): Flow<Boolean?> =
|
||||
|
@ -379,7 +383,7 @@ class SettingsDiskSourceImpl(
|
|||
isScreenCaptureAllowed: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = "${SCREEN_CAPTURE_ALLOW_KEY}_$userId",
|
||||
key = SCREEN_CAPTURE_ALLOW_KEY.appendIdentifier(userId),
|
||||
value = isScreenCaptureAllowed,
|
||||
)
|
||||
getMutableScreenCaptureAllowedFlow(userId).tryEmit(isScreenCaptureAllowed)
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.platform.datasource.disk.legacy
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseEncryptedDiskSource
|
||||
|
||||
/**
|
||||
* Primary implementation of [LegacySecureStorageMigrator].
|
||||
|
@ -21,7 +20,7 @@ class LegacySecureStorageMigratorImpl(
|
|||
// which will all start with "bwSecureStorage". Hashing only occurred on devices with
|
||||
// SDK <23.
|
||||
val plaintextKeys = keys.filter {
|
||||
it.startsWith(BaseEncryptedDiskSource.ENCRYPTED_BASE_KEY)
|
||||
it.startsWith(ENCRYPTED_BASE_KEY)
|
||||
}
|
||||
|
||||
plaintextKeys.forEach { unhashedKey ->
|
||||
|
@ -32,4 +31,8 @@ class LegacySecureStorageMigratorImpl(
|
|||
legacySecureStorage.remove(unhashedKey)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ENCRYPTED_BASE_KEY: String = "bwSecureStorage"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class GeneratorDiskSourceImpl(
|
|||
}
|
||||
|
||||
override fun getPasscodeGenerationOptions(userId: String): PasscodeGenerationOptions? =
|
||||
getString("${BASE_KEY}:${PASSWORD_GENERATION_OPTIONS_KEY}_$userId")
|
||||
getString(PASSWORD_GENERATION_OPTIONS_KEY.appendIdentifier(userId))
|
||||
?.let { json.decodeFromStringOrNull(it) }
|
||||
|
||||
override fun storePasscodeGenerationOptions(
|
||||
|
@ -34,13 +34,13 @@ class GeneratorDiskSourceImpl(
|
|||
options: PasscodeGenerationOptions?,
|
||||
) {
|
||||
putString(
|
||||
"${BASE_KEY}:${PASSWORD_GENERATION_OPTIONS_KEY}_$userId",
|
||||
PASSWORD_GENERATION_OPTIONS_KEY.appendIdentifier(userId),
|
||||
options?.let { json.encodeToString(options) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUsernameGenerationOptions(userId: String): UsernameGenerationOptions? =
|
||||
getString("${BASE_KEY}:${USERNAME_GENERATION_OPTIONS_KEY}_$userId")
|
||||
getString(USERNAME_GENERATION_OPTIONS_KEY.appendIdentifier(userId))
|
||||
?.let { json.decodeFromStringOrNull(it) }
|
||||
|
||||
override fun storeUsernameGenerationOptions(
|
||||
|
@ -48,7 +48,7 @@ class GeneratorDiskSourceImpl(
|
|||
options: UsernameGenerationOptions?,
|
||||
) {
|
||||
putString(
|
||||
"${BASE_KEY}:${USERNAME_GENERATION_OPTIONS_KEY}_$userId",
|
||||
USERNAME_GENERATION_OPTIONS_KEY.appendIdentifier(userId),
|
||||
options?.let { json.encodeToString(it) },
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue