schedule device info update in fido and oath

This commit is contained in:
Adam Velebil 2024-09-05 07:27:41 +02:00
parent 3873ec4514
commit fb2bec0b5e
No known key found for this signature in database
GPG Key ID: C9B1E4A3CBBD2E10
5 changed files with 34 additions and 11 deletions

View File

@ -30,9 +30,7 @@ import com.yubico.yubikit.core.YubiKeyDevice
import com.yubico.yubikit.core.smartcard.scp.ScpKeyParams
import com.yubico.yubikit.management.Capability
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import org.slf4j.LoggerFactory
import kotlin.coroutines.suspendCoroutine
interface DeviceListener {
// a USB device is connected

View File

@ -17,6 +17,7 @@
package com.yubico.authenticator.fido
import com.yubico.authenticator.device.DeviceManager
import com.yubico.authenticator.device.Info
import com.yubico.authenticator.fido.data.YubiKitFidoSession
import com.yubico.authenticator.yubikit.DeviceInfoHelper.Companion.getDeviceInfo
import com.yubico.authenticator.yubikit.withConnection
@ -24,11 +25,15 @@ import com.yubico.yubikit.android.transport.usb.UsbYubiKeyDevice
import com.yubico.yubikit.core.fido.FidoConnection
import com.yubico.yubikit.core.util.Result
import org.slf4j.LoggerFactory
import java.util.Timer
import java.util.TimerTask
import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.suspendCoroutine
import kotlin.concurrent.schedule
class FidoConnectionHelper(private val deviceManager: DeviceManager) {
private var pendingAction: FidoAction? = null
private var deviceInfoTimer: TimerTask? = null
fun invokePending(fidoSession: YubiKitFidoSession) {
pendingAction?.let { action ->
@ -38,6 +43,7 @@ class FidoConnectionHelper(private val deviceManager: DeviceManager) {
}
fun cancelPending() {
deviceInfoTimer?.cancel()
pendingAction?.let { action ->
action.invoke(Result.failure(CancellationException()))
pendingAction = null
@ -67,7 +73,7 @@ class FidoConnectionHelper(private val deviceManager: DeviceManager) {
block(YubiKitFidoSession(it))
}.also {
if (updateDeviceInfo) {
deviceManager.setDeviceInfo(getDeviceInfo(device))
scheduleDeviceInfoUpdate(getDeviceInfo(device))
}
}
@ -91,6 +97,14 @@ class FidoConnectionHelper(private val deviceManager: DeviceManager) {
}
}
fun scheduleDeviceInfoUpdate(deviceInfo: Info?) {
deviceInfoTimer?.cancel()
deviceInfoTimer = Timer("update-device-info", false).schedule(500) {
logger.debug("Updating device info")
deviceManager.setDeviceInfo(deviceInfo)
}
}
companion object {
private val logger = LoggerFactory.getLogger(FidoConnectionHelper::class.java)
}

View File

@ -199,7 +199,7 @@ class FidoManager(
}
if (updateDeviceInfo.getAndSet(false)) {
deviceManager.setDeviceInfo(getDeviceInfo(device))
connectionHelper.scheduleDeviceInfoUpdate(getDeviceInfo(device))
}
} catch (e: Exception) {
// something went wrong, try to get DeviceInfo from any available connection type

View File

@ -26,6 +26,7 @@ import com.yubico.authenticator.*
import com.yubico.authenticator.device.Capabilities
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.oath.data.Code
import com.yubico.authenticator.oath.data.CodeType
@ -63,10 +64,12 @@ import kotlinx.serialization.encodeToString
import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URI
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.suspendCoroutine
import kotlin.random.Random
import kotlin.concurrent.schedule
typealias OathAction = (Result<YubiKitOathSession, Exception>) -> Unit
@ -108,8 +111,10 @@ class OathManager(
private var refreshJob: Job? = null
private var addToAny = false
private val updateDeviceInfo = AtomicBoolean(false)
private var deviceInfoTimer: TimerTask? = null
override fun onPause() {
deviceInfoTimer?.cancel()
// cancel any pending actions, except for addToAny
if (!addToAny) {
pendingAction?.let {
@ -294,7 +299,7 @@ class OathManager(
)
if (updateDeviceInfo.getAndSet(false)) {
deviceManager.setDeviceInfo(getDeviceInfo(device))
scheduleDeviceInfoUpdate(getDeviceInfo(device))
}
} catch (e: Exception) {
// OATH not enabled/supported, try to get DeviceInfo over other USB interfaces
@ -675,6 +680,14 @@ class OathManager(
return credential.data
}
fun scheduleDeviceInfoUpdate(deviceInfo: Info?) {
deviceInfoTimer?.cancel()
deviceInfoTimer = Timer("update-device-info", false).schedule(500) {
logger.debug("Updating device info")
deviceManager.setDeviceInfo(deviceInfo)
}
}
private suspend fun <T> useOathSession(
unlock: Boolean = true,
updateDeviceInfo: Boolean = false,
@ -702,7 +715,7 @@ class OathManager(
block(getOathSession(it))
}.also {
if (updateDeviceInfo) {
deviceManager.setDeviceInfo(getDeviceInfo(device))
scheduleDeviceInfoUpdate(getDeviceInfo(device))
}
}

View File

@ -393,8 +393,7 @@ class _FidoMethodChannelNotifier extends MethodChannelNotifier {
Future<dynamic> reset() async => invoke('reset', {
'operationSuccess': l10n.s_nfc_fido_reset_success,
'operationFailure': l10n.s_nfc_fido_reset_failure,
'showSuccess': true
'operationFailure': l10n.s_nfc_fido_reset_failure
});
Future<dynamic> setPin(String newPin, {String? oldPin}) async =>
@ -405,8 +404,7 @@ class _FidoMethodChannelNotifier extends MethodChannelNotifier {
: l10n.s_pin_set,
'operationFailure': oldPin != null
? l10n.s_nfc_fido_change_pin_failure
: l10n.s_nfc_fido_set_pin_failure,
'showSuccess': true
: l10n.s_nfc_fido_set_pin_failure
});
Future<dynamic> unlock(String pin) async => invoke('unlock', {