From 8318b5e68b980d02c672cca08bdf47943d1ac596 Mon Sep 17 00:00:00 2001 From: Adam Velebil Date: Thu, 11 Apr 2024 14:44:18 +0200 Subject: [PATCH] only cancel reset in onStop --- .../yubico/authenticator/AppContextManager.kt | 2 - .../com/yubico/authenticator/MainActivity.kt | 3 +- .../yubico/authenticator/fido/FidoManager.kt | 30 ++++++------ .../authenticator/fido/FidoResetHelper.kt | 47 ++++++++++--------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/AppContextManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/AppContextManager.kt index eb187d83..de1a30ae 100755 --- a/android/app/src/main/kotlin/com/yubico/authenticator/AppContextManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/AppContextManager.kt @@ -27,6 +27,4 @@ abstract class AppContextManager { open fun dispose() {} open fun onPause() {} - - open fun onResume() {} } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt b/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt index d583674e..5c18841f 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt @@ -258,8 +258,6 @@ class MainActivity : FlutterFragmentActivity() { appPreferences.registerListener(sharedPreferencesListener) preserveConnectionOnPause = false - - contextManager?.onResume() } override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration) { @@ -390,6 +388,7 @@ class MainActivity : FlutterFragmentActivity() { OperationContext.FidoFingerprints, OperationContext.FidoPasskeys -> FidoManager( messenger, + this, deviceManager, fidoViewModel, viewModel, diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoManager.kt index 4a506897..d876740e 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoManager.kt @@ -16,6 +16,7 @@ package com.yubico.authenticator.fido +import androidx.lifecycle.LifecycleOwner import com.yubico.authenticator.AppContextManager import com.yubico.authenticator.DialogManager import com.yubico.authenticator.MainViewModel @@ -23,22 +24,16 @@ import com.yubico.authenticator.NULL import com.yubico.authenticator.asString import com.yubico.authenticator.device.DeviceListener import com.yubico.authenticator.device.DeviceManager -import com.yubico.authenticator.device.Info -import com.yubico.authenticator.device.UnknownDevice import com.yubico.authenticator.fido.data.FidoCredential import com.yubico.authenticator.fido.data.FidoFingerprint import com.yubico.authenticator.fido.data.Session import com.yubico.authenticator.fido.data.SessionInfo import com.yubico.authenticator.fido.data.YubiKitFidoSession import com.yubico.authenticator.setHandler -import com.yubico.authenticator.yubikit.getDeviceInfo import com.yubico.authenticator.yubikit.withConnection import com.yubico.yubikit.android.transport.nfc.NfcYubiKeyDevice -import com.yubico.yubikit.android.transport.usb.UsbYubiKeyDevice -import com.yubico.yubikit.core.Transport import com.yubico.yubikit.core.YubiKeyConnection import com.yubico.yubikit.core.YubiKeyDevice -import com.yubico.yubikit.core.application.ApplicationNotAvailableException import com.yubico.yubikit.core.application.CommandState import com.yubico.yubikit.core.fido.CtapException import com.yubico.yubikit.core.fido.FidoConnection @@ -54,7 +49,6 @@ import com.yubico.yubikit.fido.ctap.PinUvAuthDummyProtocol import com.yubico.yubikit.fido.ctap.PinUvAuthProtocol import com.yubico.yubikit.fido.ctap.PinUvAuthProtocolV1 import com.yubico.yubikit.fido.ctap.PinUvAuthProtocolV2 -import com.yubico.yubikit.support.DeviceUtil import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodChannel import kotlinx.coroutines.CoroutineScope @@ -71,6 +65,7 @@ typealias FidoAction = (Result) -> Unit class FidoManager( messenger: BinaryMessenger, + lifecycleOwner: LifecycleOwner, private val deviceManager: DeviceManager, private val fidoViewModel: FidoViewModel, mainViewModel: MainViewModel, @@ -115,15 +110,14 @@ class FidoManager( private var pinRetries : Int? = null private val resetHelper = - FidoResetHelper(deviceManager, fidoViewModel, mainViewModel, connectionHelper, pinStore) - - override fun onPause() { - resetHelper.onPause() - } - - override fun onResume() { - resetHelper.onResume() - } + FidoResetHelper( + lifecycleOwner, + deviceManager, + fidoViewModel, + mainViewModel, + connectionHelper, + pinStore + ) init { pinRetries = null @@ -227,6 +221,10 @@ class FidoManager( logger.debug("This is a different key than previous, invalidating the PIN token") pinStore.setPin(null) connectionHelper.cancelPending() + if (resetHelper.inProgress) { + logger.debug("Cannot reset this key") + resetHelper.cancelReset() + } } val infoData = fidoSession.cachedInfo diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoResetHelper.kt b/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoResetHelper.kt index b6c883e1..a89a8526 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoResetHelper.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/fido/FidoResetHelper.kt @@ -16,6 +16,8 @@ package com.yubico.authenticator.fido +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import com.yubico.authenticator.MainViewModel import com.yubico.authenticator.NULL import com.yubico.authenticator.device.DeviceManager @@ -29,14 +31,11 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import kotlinx.serialization.Serializable -import org.json.JSONObject import org.slf4j.LoggerFactory import java.io.IOException -import java.util.Timer -import java.util.TimerTask import java.util.concurrent.Executors -import kotlin.concurrent.schedule import kotlin.coroutines.cancellation.CancellationException import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -67,6 +66,7 @@ fun createCaptureErrorEvent(code: Int) : FidoRegisterFpCaptureErrorEvent { } class FidoResetHelper( + private val lifecycleOwner: LifecycleOwner, private val deviceManager: DeviceManager, private val fidoViewModel: FidoViewModel, private val mainViewModel: MainViewModel, @@ -81,8 +81,21 @@ class FidoResetHelper( private var resetCommandState: CommandState? = null private var cancelReset: Boolean = false + private val lifecycleObserver = object : DefaultLifecycleObserver { + override fun onStop(owner: LifecycleOwner) { + super.onStop(owner) + if (inProgress) { + logger.debug("Cancelling ongoing reset") + cancelReset() + } + } + } + suspend fun reset(): String { try { + withContext(Dispatchers.Main) { + lifecycleOwner.lifecycle.addObserver(lifecycleObserver) + } deviceManager.clearDeviceInfoOnDisconnect = false inProgress = true fidoViewModel.updateResetState(FidoResetState.Remove) @@ -96,6 +109,9 @@ class FidoResetHelper( } catch (e: CancellationException) { logger.debug("FIDO reset cancelled") } finally { + withContext(Dispatchers.Main) { + lifecycleOwner.lifecycle.removeObserver(lifecycleObserver) + } inProgress = false deviceManager.clearDeviceInfoOnDisconnect = true } @@ -109,21 +125,6 @@ class FidoResetHelper( return NULL } - private var cancellationTimer: TimerTask? = null - fun onPause() { - cancellationTimer?.cancel() - cancellationTimer = Timer().schedule(300) { - // the timer has not been cancelled at this point, - // the application is in PAUSED state longer than 300ms - // cancel ongoing reset - cancelReset() - } - } - - fun onResume() { - cancellationTimer?.cancel() - } - private suspend fun waitForUsbDisconnect() = suspendCoroutine { continuation -> coroutineScope.launch { cancelReset = false @@ -165,8 +166,12 @@ class FidoResetHelper( connectionHelper.useSessionUsb(usbYubiKeyDevice) { fidoSession -> resetCommandState = CommandState() try { - doReset(fidoSession) - continuation.resume(Unit) + if (cancelReset) { + continuation.resumeWithException(CancellationException()) + } else { + doReset(fidoSession) + continuation.resume(Unit) + } } catch (e: CtapException) { when (e.ctapError) { CtapException.ERR_KEEPALIVE_CANCEL -> {