fix: preserve login input during preference load

This commit is contained in:
2026-08-23 23:02:01 +08:00
parent 3764acb7ec
commit 344fa6dafa
4 changed files with 99 additions and 15 deletions
@@ -44,8 +44,16 @@ class KeystoreCredentialStore(
DomainResult.Success(decode(cipher.decrypt(profileId, encrypted)))
} catch (error: Exception) {
if (error.isPermanentCredentialFailure()) {
dataStore.edit { it.remove(credentialKey(profileId)) }
DomainResult.Success(null)
try {
dataStore.edit { it.remove(credentialKey(profileId)) }
DomainResult.Success(null)
} catch (cleanupError: Exception) {
DomainResult.Failure(
DomainError.Unknown(
detail = cleanupError.message ?: cleanupError::class.java.simpleName,
),
)
}
} else {
DomainResult.Failure(
DomainError.Unknown(detail = error.message ?: error::class.java.simpleName),
@@ -0,0 +1,43 @@
package com.flagship.abox.manager.session
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import com.flagship.abox.manager.domain.DomainResult
import com.flagship.abox.manager.domain.ProviderProfileId
import com.flagship.abox.manager.session.credential.CredentialCipher
import com.flagship.abox.manager.session.credential.KeystoreCredentialStore
import java.io.IOException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class CredentialCleanupFailureTest {
@Test
fun cleanupFailureReturnsDomainFailureInsteadOfThrowing() = runTest {
val store = KeystoreCredentialStore(FailingCleanupDataStore(), UnusedCipher())
val result = store.loadCredentials(ProviderProfileId("profile"))
assertTrue(result is DomainResult.Failure)
assertEquals("disk unavailable", (result as DomainResult.Failure).error.detail)
}
private class FailingCleanupDataStore : DataStore<Preferences> {
override val data: Flow<Preferences> = flow {
throw IllegalArgumentException("corrupt credential")
}
override suspend fun updateData(
transform: suspend (t: Preferences) -> Preferences,
): Preferences = throw IOException("disk unavailable")
}
private class UnusedCipher : CredentialCipher {
override fun encrypt(profileId: ProviderProfileId, plaintext: ByteArray): ByteArray = plaintext
override fun decrypt(profileId: ProviderProfileId, encrypted: ByteArray): ByteArray = encrypted
}
}