fix: align session state across transitions

This commit is contained in:
2026-08-24 01:47:53 +08:00
parent d893a74bec
commit a0f55b041a
8 changed files with 26 additions and 5 deletions
@@ -40,6 +40,11 @@ class AndroidKeystoreCredentialCipher(
return cipher.doFinal(ciphertext)
}
override fun resetPermanentlyInvalidatedKey() {
val keyStore = KeyStore.getInstance(ANDROID_KEY_STORE).apply { load(null) }
if (keyStore.containsAlias(keyAlias)) keyStore.deleteEntry(keyAlias)
}
private fun secretKey(): SecretKey {
val keyStore = KeyStore.getInstance(ANDROID_KEY_STORE).apply { load(null) }
(keyStore.getKey(keyAlias, null) as? SecretKey)?.let { return it }
@@ -6,4 +6,6 @@ interface CredentialCipher {
fun encrypt(profileId: ProviderProfileId, plaintext: ByteArray): ByteArray
fun decrypt(profileId: ProviderProfileId, encrypted: ByteArray): ByteArray
fun resetPermanentlyInvalidatedKey()
}
@@ -46,6 +46,9 @@ class KeystoreCredentialStore(
} catch (error: Exception) {
if (error.isPermanentCredentialFailure()) {
try {
if (error.hasPermanentlyInvalidatedKey()) {
cipher.resetPermanentlyInvalidatedKey()
}
dataStore.edit { it.remove(credentialKey(profileId)) }
DomainResult.Success(null)
} catch (cleanupError: CancellationException) {
@@ -122,6 +125,9 @@ private fun DataInputStream.readByteArray(maxSize: Int): ByteArray {
return ByteArray(length).also(::readFully)
}
private fun Throwable.hasPermanentlyInvalidatedKey(): Boolean =
this is KeyPermanentlyInvalidatedException || cause?.hasPermanentlyInvalidatedKey() == true
private fun Throwable.isPermanentCredentialFailure(): Boolean = when (this) {
is AEADBadTagException,
is KeyPermanentlyInvalidatedException,
@@ -39,5 +39,7 @@ class CredentialCleanupFailureTest {
override fun encrypt(profileId: ProviderProfileId, plaintext: ByteArray): ByteArray = plaintext
override fun decrypt(profileId: ProviderProfileId, encrypted: ByteArray): ByteArray = encrypted
override fun resetPermanentlyInvalidatedKey() = Unit
}
}
@@ -69,6 +69,8 @@ class CredentialStoreTest {
override fun decrypt(profileId: ProviderProfileId, encrypted: ByteArray): ByteArray {
throw IllegalArgumentException("Credential payload is truncated")
}
override fun resetPermanentlyInvalidatedKey() = Unit
}
private class ReversingCipher : CredentialCipher {
@@ -81,5 +83,7 @@ class CredentialStoreTest {
require(decoded.copyOfRange(0, delimiter).decodeToString() == profileId.value)
return decoded.copyOfRange(delimiter + 1, decoded.size)
}
override fun resetPermanentlyInvalidatedKey() = Unit
}
}