From d4993a36338456706ba22823848bb51eb8287a07 Mon Sep 17 00:00:00 2001 From: mimi89999 Date: Sat, 20 Dec 2025 21:25:21 +0100 Subject: [PATCH] Wrap getPinRetries in Result to propagate errors --- .../authnkey/CredentialProviderActivity.kt | 8 ++++---- .../java/pl/lebihan/authnkey/MainActivity.kt | 7 +++---- .../main/java/pl/lebihan/authnkey/PinProtocol.kt | 16 +++++++++++----- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt b/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt index c30ec59..e8f30c3 100644 --- a/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt +++ b/app/src/main/java/pl/lebihan/authnkey/CredentialProviderActivity.kt @@ -456,12 +456,12 @@ class CredentialProviderActivity : AppCompatActivity() { } // UV required/preferred and device has PIN - need to get PIN userVerification != UserVerification.DISCOURAGED && deviceHasPin -> { - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } ?: 8 + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrDefault(8) showPinDialog(retries, json) } // UV discouraged but device has alwaysUv - need PIN anyway userVerification == UserVerification.DISCOURAGED && alwaysUv && deviceHasPin -> { - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } ?: 8 + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrDefault(8) showPinDialog(retries, json) } // UV discouraged or preferred with no PIN - try without @@ -487,7 +487,7 @@ class CredentialProviderActivity : AppCompatActivity() { e.error == CTAP.Error.PIN_AUTH_INVALID) { Log.d(TAG, "Authenticator requires PIN despite UV=discouraged") val protocol = pinProtocol ?: throw Exception("No PIN protocol") - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } ?: 8 + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrDefault(8) showPinDialog(retries, json) } else { throw e @@ -535,7 +535,7 @@ class CredentialProviderActivity : AppCompatActivity() { protocol.getPinToken(pin, permissions, rpId) } if (!authenticated) { - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } ?: 0 + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrThrow() if (retries > 0) { runOnUiThread { showProgress(false) diff --git a/app/src/main/java/pl/lebihan/authnkey/MainActivity.kt b/app/src/main/java/pl/lebihan/authnkey/MainActivity.kt index a3d360c..550f7c1 100644 --- a/app/src/main/java/pl/lebihan/authnkey/MainActivity.kt +++ b/app/src/main/java/pl/lebihan/authnkey/MainActivity.kt @@ -427,9 +427,8 @@ class MainActivity : AppCompatActivity() { } val protocol = pinProtocol ?: throw Exception("PIN protocol not initialized") - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } - - if (retries == null) { + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrElse { e -> + if (e is java.io.IOException) throw e resultText.text = getString(R.string.error_could_not_get_pin_status) pendingAction = null return@launch @@ -626,7 +625,7 @@ class MainActivity : AppCompatActivity() { resultText.text = getString(R.string.checking_pin_status) - val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() } + val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrNull() val dialogView = layoutInflater.inflate(R.layout.dialog_pin, null) val currentPinEdit = dialogView.findViewById(R.id.currentPin) diff --git a/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt b/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt index fd2f62c..3a1cdae 100644 --- a/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt +++ b/app/src/main/java/pl/lebihan/authnkey/PinProtocol.kt @@ -125,18 +125,24 @@ class PinProtocol(private val transport: FidoTransport) { } } - suspend fun getPinRetries(): Int? { - try { + suspend fun getPinRetries(): Result { + return try { val response = transport.sendCtapCommand(CTAP.buildGetPinRetriesCommand()) if (!CTAP.isSuccess(response)) { - return null + return Result.failure(CTAP.Exception( + CTAP.getResponseError(response) ?: CTAP.Error.OTHER + )) } val data = response.drop(1).toByteArray() val parsed = CborMap.decode(data) - return parsed?.int(3) + ?: return Result.failure(Exception("Failed to parse response")) + val retries = parsed.int(3) + ?: return Result.failure(Exception("Missing retries field")) + + Result.success(retries) } catch (e: Exception) { - return null + Result.failure(e) } }