Add clearData calls DiskSources (#603)

This commit is contained in:
Brian Yencho 2024-01-14 08:19:11 -06:00 committed by Álison Fernandes
parent 67d7b7a9f5
commit f1b9ded3e3
12 changed files with 161 additions and 12 deletions

View file

@ -31,6 +31,13 @@ interface AuthDiskSource {
*/
val userStateFlow: Flow<UserStateJson?>
/**
* Clears all the settings data for the given user.
*
* Note that this does not include any data saved in the [userState].
*/
fun clearData(userId: String)
/**
* Retrieves the "last active time" for the given [userId], in milliseconds.
*

View file

@ -67,6 +67,17 @@ class AuthDiskSourceImpl(
get() = mutableUserStateFlow
.onSubscription { emit(userState) }
private val mutableUserStateFlow = bufferedMutableSharedFlow<UserStateJson?>(replay = 1)
override fun clearData(userId: String) {
storeLastActiveTimeMillis(userId = userId, lastActiveTimeMillis = null)
storeUserKey(userId = userId, userKey = null)
storeUserAutoUnlockKey(userId = userId, userAutoUnlockKey = null)
storePrivateKey(userId = userId, privateKey = null)
storeOrganizationKeys(userId = userId, organizationKeys = null)
storeOrganizations(userId = userId, organizations = null)
}
override fun getLastActiveTimeMillis(userId: String): Long? =
getLong(key = "${LAST_ACTIVE_TIME_KEY}_$userId")
@ -80,8 +91,6 @@ class AuthDiskSourceImpl(
)
}
private val mutableUserStateFlow = bufferedMutableSharedFlow<UserStateJson?>(replay = 1)
override fun getUserKey(userId: String): String? =
getString(key = "${MASTER_KEY_ENCRYPTION_USER_KEY}_$userId")

View file

@ -13,6 +13,11 @@ interface SettingsDiskSource {
*/
var appLanguage: AppLanguage?
/**
* Clears all the settings data for the given user.
*/
fun clearData(userId: String)
/**
* Gets the current vault timeout (in minutes) for the given [userId] (or `null` if the vault
* should never time out).

View file

@ -39,6 +39,11 @@ class SettingsDiskSourceImpl(
)
}
override fun clearData(userId: String) {
storeVaultTimeoutInMinutes(userId = userId, vaultTimeoutInMinutes = null)
storeVaultTimeoutAction(userId = userId, vaultTimeoutAction = null)
}
override fun getVaultTimeoutInMinutes(userId: String): Int? =
getInt(key = "${VAULT_TIME_IN_MINUTES_KEY}_$userId")

View file

@ -59,16 +59,7 @@ class SettingsRepositoryImpl(
}
override fun clearData(userId: String) {
settingsDiskSource.apply {
storeVaultTimeoutInMinutes(
userId = userId,
vaultTimeoutInMinutes = null,
)
storeVaultTimeoutAction(
userId = userId,
vaultTimeoutAction = null,
)
}
settingsDiskSource.clearData(userId = userId)
}
override fun setDefaultsIfNecessary(userId: String) {

View file

@ -7,6 +7,10 @@ import com.x8bit.bitwarden.data.tools.generator.repository.model.UsernameGenerat
* Primary access point for disk information related to generation.
*/
interface GeneratorDiskSource {
/**
* Clears all the settings data for the given user.
*/
fun clearData(userId: String)
/**
* Retrieves a user's passcode generation options using a [userId].

View file

@ -19,6 +19,11 @@ class GeneratorDiskSourceImpl(
) : BaseDiskSource(sharedPreferences),
GeneratorDiskSource {
override fun clearData(userId: String) {
storePasscodeGenerationOptions(userId = userId, options = null)
storeUsernameGenerationOptions(userId = userId, options = null)
}
override fun getPasscodeGenerationOptions(userId: String): PasscodeGenerationOptions? {
val key = getPasswordGenerationOptionsKey(userId)
return getString(key)?.let { json.decodeFromString(it) }

View file

@ -118,6 +118,39 @@ class AuthDiskSourceTest {
}
}
@Test
fun `clearData should clear all necessary data for the given user`() {
val userId = "userId"
authDiskSource.storeLastActiveTimeMillis(
userId = userId,
lastActiveTimeMillis = 123456789L,
)
authDiskSource.storeUserKey(userId = userId, userKey = "userKey")
authDiskSource.storeUserAutoUnlockKey(
userId = userId,
userAutoUnlockKey = "userAutoUnlockKey",
)
authDiskSource.storePrivateKey(userId = userId, privateKey = "privateKey")
authDiskSource.storeOrganizationKeys(
userId = userId,
organizationKeys = mapOf("organizationId" to "key"),
)
authDiskSource.storeOrganizations(
userId = userId,
organizations = listOf(createMockOrganization(1)),
)
authDiskSource.clearData(userId = userId)
assertNull(authDiskSource.getLastActiveTimeMillis(userId = userId))
assertNull(authDiskSource.getUserKey(userId = userId))
assertNull(authDiskSource.getUserAutoUnlockKey(userId = userId))
assertNull(authDiskSource.getPrivateKey(userId = userId))
assertNull(authDiskSource.getOrganizationKeys(userId = userId))
assertNull(authDiskSource.getOrganizations(userId = userId))
}
@Test
fun `getLastActiveTimeMillis should pull from SharedPreferences`() {
val lastActiveTimeBaseKey = "bwPreferencesStorage:lastActiveTime"

View file

@ -36,6 +36,17 @@ class FakeAuthDiskSource : AuthDiskSource {
override val userStateFlow: Flow<UserStateJson?>
get() = mutableUserStateFlow.onSubscription { emit(userState) }
override fun clearData(userId: String) {
storedLastActiveTimeMillis.remove(userId)
storedUserKeys.remove(userId)
storedPrivateKeys.remove(userId)
storedUserAutoUnlockKeys.remove(userId)
storedOrganizations.remove(userId)
storedOrganizationKeys.remove(userId)
mutableOrganizationsFlowMap.remove(userId)
}
override fun getLastActiveTimeMillis(userId: String): Long? =
storedLastActiveTimeMillis[userId]

View file

@ -58,6 +58,24 @@ class SettingsDiskSourceTest {
)
}
@Test
fun `clearData should clear all necessary data for the given user`() {
val userId = "userId"
settingsDiskSource.storeVaultTimeoutInMinutes(
userId = userId,
vaultTimeoutInMinutes = 30,
)
settingsDiskSource.storeVaultTimeoutAction(
userId = userId,
vaultTimeoutAction = VaultTimeoutAction.LOCK,
)
settingsDiskSource.clearData(userId = userId)
assertNull(settingsDiskSource.getVaultTimeoutInMinutes(userId = userId))
assertNull(settingsDiskSource.getVaultTimeoutAction(userId = userId))
}
@Test
fun `getVaultTimeoutInMinutes when values are present should pull from SharedPreferences`() {
val vaultTimeoutBaseKey = "bwPreferencesStorage:vaultTimeout"

View file

@ -24,6 +24,14 @@ class FakeSettingsDiskSource : SettingsDiskSource {
override var appLanguage: AppLanguage? = null
override fun clearData(userId: String) {
storedVaultTimeoutActions.remove(userId)
storedVaultTimeoutInMinutes.remove(userId)
mutableVaultTimeoutActionsFlowMap.remove(userId)
mutableVaultTimeoutInMinutesFlowMap.remove(userId)
}
override fun getVaultTimeoutInMinutes(userId: String): Int? =
storedVaultTimeoutInMinutes[userId]

View file

@ -25,6 +25,59 @@ class GeneratorDiskSourceTest {
json = json,
)
@Test
fun `clearData should clear all necessary data for the given user`() {
val userId = "userId"
val passcodeOptions = PasscodeGenerationOptions(
length = 14,
allowAmbiguousChar = false,
hasNumbers = true,
minNumber = 0,
hasUppercase = true,
minUppercase = null,
hasLowercase = false,
minLowercase = null,
allowSpecial = false,
minSpecial = 1,
allowCapitalize = false,
allowIncludeNumber = false,
wordSeparator = "-",
numWords = 3,
)
val userNameOptions = UsernameGenerationOptions(
type = UsernameGenerationOptions.UsernameType.RANDOM_WORD,
serviceType = UsernameGenerationOptions.ForwardedEmailServiceType.NONE,
capitalizeRandomWordUsername = true,
includeNumberRandomWordUsername = false,
plusAddressedEmail = "example+plus@gmail.com",
catchAllEmailDomain = "example.com",
firefoxRelayApiAccessToken = "access_token_firefox_relay",
simpleLoginApiKey = "api_key_simple_login",
duckDuckGoApiKey = "api_key_duck_duck_go",
fastMailApiKey = "api_key_fast_mail",
anonAddyApiAccessToken = "access_token_anon_addy",
anonAddyDomainName = "anonaddy.com",
forwardEmailApiAccessToken = "access_token_forward_email",
forwardEmailDomainName = "forwardemail.net",
emailWebsite = "email.example.com",
)
generatorDiskSource.storePasscodeGenerationOptions(
userId = userId,
options = passcodeOptions,
)
generatorDiskSource.storeUsernameGenerationOptions(
userId = userId,
options = userNameOptions,
)
generatorDiskSource.clearData(userId = userId)
assertNull(generatorDiskSource.getPasscodeGenerationOptions(userId = userId))
assertNull(generatorDiskSource.getUsernameGenerationOptions(userId = userId))
}
@Test
fun `getPasscodeGenerationOptions should return correct options when available`() {
val userId = "user123"