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 1e5dfc4e..968dc671 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/MainActivity.kt @@ -51,9 +51,9 @@ import com.yubico.authenticator.management.ManagementHandler import com.yubico.authenticator.oath.AppLinkMethodChannel import com.yubico.authenticator.oath.OathManager import com.yubico.authenticator.oath.OathViewModel -import com.yubico.authenticator.yubikit.NfcActivityDispatcher -import com.yubico.authenticator.yubikit.NfcActivityListener -import com.yubico.authenticator.yubikit.NfcActivityState +import com.yubico.authenticator.yubikit.NfcStateDispatcher +import com.yubico.authenticator.yubikit.NfcStateListener +import com.yubico.authenticator.yubikit.NfcState import com.yubico.authenticator.yubikit.DeviceInfoHelper.Companion.getDeviceInfo import com.yubico.authenticator.yubikit.withConnection import com.yubico.yubikit.android.YubiKitManager @@ -79,7 +79,6 @@ import kotlinx.coroutines.launch import org.json.JSONObject import org.slf4j.LoggerFactory import java.io.Closeable -import java.io.IOException import java.security.NoSuchAlgorithmException import java.util.concurrent.Executors import javax.crypto.Mac @@ -104,16 +103,16 @@ class MainActivity : FlutterFragmentActivity() { private val logger = LoggerFactory.getLogger(MainActivity::class.java) - private val nfcActivityListener = object : NfcActivityListener { + private val nfcStateListener = object : NfcStateListener { var appMethodChannel : AppMethodChannel? = null - override fun onChange(newState: NfcActivityState) { + override fun onChange(newState: NfcState) { appMethodChannel?.let { - logger.debug("setting nfc activity state to ${newState.name}") - it.nfcActivityStateChanged(newState) + logger.debug("set nfc state to ${newState.name}") + it.nfcStateChanged(newState) } ?: { - logger.warn("cannot set nfc activity state to ${newState.name} - no method channel") + logger.warn("failed set nfc state to ${newState.name} - no method channel") } } } @@ -131,7 +130,7 @@ class MainActivity : FlutterFragmentActivity() { yubikit = YubiKitManager( UsbYubiKeyManager(this), - NfcYubiKeyManager(this, NfcActivityDispatcher(nfcActivityListener)) + NfcYubiKeyManager(this, NfcStateDispatcher(nfcStateListener)) ) } @@ -319,7 +318,7 @@ class MainActivity : FlutterFragmentActivity() { } if (device is NfcYubiKeyDevice) { - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_STARTED) + appMethodChannel.nfcStateChanged(NfcState.ONGOING) } // If NFC and FIPS check for SCP11b key @@ -342,7 +341,7 @@ class MainActivity : FlutterFragmentActivity() { } catch (e: Exception) { logger.debug("Exception while getting scp keys: ", e) if (device is NfcYubiKeyDevice) { - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_INTERRUPTED) + appMethodChannel.nfcStateChanged(NfcState.FAILURE) } null } @@ -376,14 +375,14 @@ class MainActivity : FlutterFragmentActivity() { try { it.processYubiKey(device) if (!switchedContext && device is NfcYubiKeyDevice) { - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_FINISHED) + appMethodChannel.nfcStateChanged(NfcState.SUCCESS) device.remove { - appMethodChannel.nfcActivityStateChanged(NfcActivityState.READY) + appMethodChannel.nfcStateChanged(NfcState.IDLE) } } } catch (e: Exception) { logger.debug("Caught Exception during YubiKey processing: ", e) - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_INTERRUPTED) + appMethodChannel.nfcStateChanged(NfcState.FAILURE) } } } @@ -420,7 +419,7 @@ class MainActivity : FlutterFragmentActivity() { appLinkMethodChannel = AppLinkMethodChannel(messenger) managementHandler = ManagementHandler(messenger, deviceManager) - nfcActivityListener.appMethodChannel = appMethodChannel + nfcStateListener.appMethodChannel = appMethodChannel flutterStreams = listOf( viewModel.deviceInfo.streamTo(this, messenger, "android.devices.deviceInfo"), @@ -486,7 +485,7 @@ class MainActivity : FlutterFragmentActivity() { } override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) { - nfcActivityListener.appMethodChannel = null + nfcStateListener.appMethodChannel = null flutterStreams.forEach { it.close() } contextManager?.dispose() deviceManager.dispose() @@ -626,14 +625,14 @@ class MainActivity : FlutterFragmentActivity() { fun nfcAdapterStateChanged(value: Boolean) { methodChannel.invokeMethod( "nfcAdapterStateChanged", - JSONObject(mapOf("nfcEnabled" to value)).toString() + JSONObject(mapOf("enabled" to value)).toString() ) } - fun nfcActivityStateChanged(activityState: NfcActivityState) { + fun nfcStateChanged(activityState: NfcState) { lifecycleScope.launch(Dispatchers.Main) { methodChannel.invokeMethod( - "nfcActivityChanged", + "nfcStateChanged", JSONObject(mapOf("state" to activityState.value)).toString() ) } diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/device/DeviceManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/device/DeviceManager.kt index 0eab6c77..8eba8e65 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/device/DeviceManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/device/DeviceManager.kt @@ -25,7 +25,7 @@ import com.yubico.authenticator.DialogManager import com.yubico.authenticator.MainActivity import com.yubico.authenticator.MainViewModel import com.yubico.authenticator.OperationContext -import com.yubico.authenticator.yubikit.NfcActivityState +import com.yubico.authenticator.yubikit.NfcState import com.yubico.yubikit.android.transport.usb.UsbYubiKeyDevice import com.yubico.yubikit.core.YubiKeyDevice import com.yubico.yubikit.core.smartcard.scp.ScpKeyParams @@ -222,11 +222,11 @@ class DeviceManager( if (e is ContextDisposedException) { // the key does not have the needed context anymore // we cannot continue - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_INTERRUPTED) + appMethodChannel.nfcStateChanged(NfcState.FAILURE) throw e } - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_INTERRUPTED) + appMethodChannel.nfcStateChanged(NfcState.FAILURE) } } } @@ -242,7 +242,7 @@ class DeviceManager( try { return onNfc.invoke().value } catch (e: Exception) { - appMethodChannel.nfcActivityStateChanged(NfcActivityState.PROCESSING_INTERRUPTED) + appMethodChannel.nfcStateChanged(NfcState.FAILURE) throw e } } 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 df6a15fe..badddb11 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 @@ -25,7 +25,6 @@ import com.yubico.authenticator.NULL import com.yubico.authenticator.device.DeviceManager import com.yubico.authenticator.fido.data.Session import com.yubico.authenticator.fido.data.YubiKitFidoSession -import com.yubico.authenticator.yubikit.NfcActivityState import com.yubico.yubikit.core.application.CommandState import com.yubico.yubikit.core.fido.CtapException import kotlinx.coroutines.CoroutineScope diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityState.kt b/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcState.kt similarity index 75% rename from android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityState.kt rename to android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcState.kt index 3d6af5fa..670acf66 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityState.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcState.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Yubico. + * Copyright (C) 2023-2024 Yubico. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,10 @@ package com.yubico.authenticator.yubikit -enum class NfcActivityState(val value: Int) { - NOT_ACTIVE(0), - READY(1), - PROCESSING_STARTED(2), - PROCESSING_FINISHED(3), - PROCESSING_INTERRUPTED(4) +enum class NfcState(val value: Int) { + DISABLED(0), + IDLE(1), + ONGOING(2), + SUCCESS(3), + FAILURE(4) } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityDispatcher.kt b/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcStateDispatcher.kt similarity index 57% rename from android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityDispatcher.kt rename to android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcStateDispatcher.kt index cea74967..d825bb0e 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcActivityDispatcher.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/yubikit/NfcStateDispatcher.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Yubico. + * Copyright (C) 2023-2024 Yubico. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,6 @@ package com.yubico.authenticator.yubikit import android.app.Activity import android.nfc.NfcAdapter -import android.nfc.Tag -import com.yubico.authenticator.yubikit.NfcActivityListener import com.yubico.yubikit.android.transport.nfc.NfcConfiguration import com.yubico.yubikit.android.transport.nfc.NfcDispatcher @@ -27,16 +25,16 @@ import com.yubico.yubikit.android.transport.nfc.NfcReaderDispatcher import org.slf4j.LoggerFactory -interface NfcActivityListener { - fun onChange(newState: NfcActivityState) +interface NfcStateListener { + fun onChange(newState: NfcState) } -class NfcActivityDispatcher(private val listener: NfcActivityListener) : NfcDispatcher { +class NfcStateDispatcher(private val listener: NfcStateListener) : NfcDispatcher { private lateinit var adapter: NfcAdapter private lateinit var yubikitNfcDispatcher: NfcReaderDispatcher - private val logger = LoggerFactory.getLogger(NfcActivityDispatcher::class.java) + private val logger = LoggerFactory.getLogger(NfcStateDispatcher::class.java) override fun enable( activity: Activity, @@ -46,33 +44,17 @@ class NfcActivityDispatcher(private val listener: NfcActivityListener) : NfcDisp adapter = NfcAdapter.getDefaultAdapter(activity) yubikitNfcDispatcher = NfcReaderDispatcher(adapter) - logger.debug("enabling yubikit NFC activity dispatcher") + logger.debug("enabling yubikit NFC state dispatcher") yubikitNfcDispatcher.enable( activity, nfcConfiguration, - TagInterceptor(listener, handler) + handler ) - //listener.onChange(NfcActivityState.READY) } override fun disable(activity: Activity) { - listener.onChange(NfcActivityState.NOT_ACTIVE) + listener.onChange(NfcState.DISABLED) yubikitNfcDispatcher.disable(activity) - logger.debug("disabling yubikit NFC activity dispatcher") - } - - class TagInterceptor( - private val listener: NfcActivityListener, - private val tagHandler: NfcDispatcher.OnTagHandler - ) : NfcDispatcher.OnTagHandler { - - private val logger = LoggerFactory.getLogger(TagInterceptor::class.java) - - override fun onTag(tag: Tag) { - //listener.onChange(NfcActivityState.PROCESSING_STARTED) - logger.debug("forwarding tag") - tagHandler.onTag(tag) - } - + logger.debug("disabling yubikit NFC state dispatcher") } } \ No newline at end of file diff --git a/lib/android/app_methods.dart b/lib/android/app_methods.dart index 5d6c01b9..d152d82a 100644 --- a/lib/android/app_methods.dart +++ b/lib/android/app_methods.dart @@ -18,6 +18,7 @@ import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../theme.dart'; import 'state.dart'; @@ -73,16 +74,14 @@ void setupAppMethodsChannel(WidgetRef ref) { switch (call.method) { case 'nfcAdapterStateChanged': { - var nfcEnabled = args['nfcEnabled']; - ref.read(androidNfcStateProvider.notifier).setNfcEnabled(nfcEnabled); + var enabled = args['enabled']; + ref.read(androidNfcAdapterState.notifier).enable(enabled); break; } - case 'nfcActivityChanged': + case 'nfcStateChanged': { - var nfcActivityState = args['state']; - ref - .read(androidNfcActivityProvider.notifier) - .setActivityState(nfcActivityState); + var nfcState = args['state']; + ref.read(androidNfcState.notifier).set(nfcState); break; } default: diff --git a/lib/android/overlay/nfc/nfc_overlay_provider.dart b/lib/android/overlay/nfc/nfc_overlay_provider.dart index 80958942..f068017e 100755 --- a/lib/android/overlay/nfc/nfc_overlay_provider.dart +++ b/lib/android/overlay/nfc/nfc_overlay_provider.dart @@ -40,12 +40,12 @@ class _NfcOverlayProvider extends Notifier { @override int build() { - ref.listen(androidNfcActivityProvider, (previous, current) { + ref.listen(androidNfcState, (previous, current) { processingViewTimeout?.cancel(); final notifier = ref.read(nfcEventNotifier.notifier); switch (current) { - case NfcActivity.processingStarted: + case NfcState.ongoing: // the "Hold still..." view will be shown after this timeout // if the action is finished before, the timer might be cancelled // causing the view not to be visible at all @@ -55,19 +55,20 @@ class _NfcOverlayProvider extends Notifier { notifier.send(showHoldStill()); }); break; - case NfcActivity.processingFinished: + case NfcState.success: notifier.send(showDone()); notifier .send(const NfcHideViewEvent(delay: Duration(milliseconds: 400))); break; - case NfcActivity.processingInterrupted: + case NfcState.failure: notifier.send(showFailed()); break; - case NfcActivity.notActive: - _log.debug('Received not handled notActive'); + case NfcState.disabled: + _log.debug('Received state: disabled'); + break; + case NfcState.idle: + _log.debug('Received state: idle'); break; - case NfcActivity.ready: - _log.debug('Received not handled ready'); } }); diff --git a/lib/android/state.dart b/lib/android/state.dart index 606d6c85..4ccc15bd 100644 --- a/lib/android/state.dart +++ b/lib/android/state.dart @@ -69,33 +69,33 @@ class _AndroidClipboard extends AppClipboard { } } -class NfcStateNotifier extends StateNotifier { - NfcStateNotifier() : super(false); +class NfcAdapterState extends StateNotifier { + NfcAdapterState() : super(false); - void setNfcEnabled(bool value) { + void enable(bool value) { state = value; } } -enum NfcActivity { - notActive, - ready, - processingStarted, - processingFinished, - processingInterrupted, +enum NfcState { + disabled, + idle, + ongoing, + success, + failure, } -class NfcActivityNotifier extends StateNotifier { - NfcActivityNotifier() : super(NfcActivity.notActive); +class NfcStateNotifier extends StateNotifier { + NfcStateNotifier() : super(NfcState.disabled); - void setActivityState(int stateValue) { + void set(int stateValue) { var newState = switch (stateValue) { - 0 => NfcActivity.notActive, - 1 => NfcActivity.ready, - 2 => NfcActivity.processingStarted, - 3 => NfcActivity.processingFinished, - 4 => NfcActivity.processingInterrupted, - _ => NfcActivity.notActive + 0 => NfcState.disabled, + 1 => NfcState.idle, + 2 => NfcState.ongoing, + 3 => NfcState.success, + 4 => NfcState.failure, + _ => NfcState.disabled }; state = newState; @@ -108,12 +108,11 @@ final androidSdkVersionProvider = Provider((ref) => -1); final androidNfcSupportProvider = Provider((ref) => false); -final androidNfcStateProvider = - StateNotifierProvider((ref) => NfcStateNotifier()); +final androidNfcAdapterState = + StateNotifierProvider((ref) => NfcAdapterState()); -final androidNfcActivityProvider = - StateNotifierProvider( - (ref) => NfcActivityNotifier()); +final androidNfcState = StateNotifierProvider( + (ref) => NfcStateNotifier()); final androidSupportedThemesProvider = StateProvider>((ref) { if (ref.read(androidSdkVersionProvider) < 29) { @@ -220,6 +219,7 @@ class NfcTapActionNotifier extends StateNotifier { static const _prefNfcOpenApp = 'prefNfcOpenApp'; static const _prefNfcCopyOtp = 'prefNfcCopyOtp'; final SharedPreferences _prefs; + NfcTapActionNotifier._(this._prefs, super._state); factory NfcTapActionNotifier(SharedPreferences prefs) { @@ -261,6 +261,7 @@ class NfcKbdLayoutNotifier extends StateNotifier { static const String _defaultClipKbdLayout = 'US'; static const _prefClipKbdLayout = 'prefClipKbdLayout'; final SharedPreferences _prefs; + NfcKbdLayoutNotifier(this._prefs) : super(_prefs.getString(_prefClipKbdLayout) ?? _defaultClipKbdLayout); @@ -279,6 +280,7 @@ final androidNfcBypassTouchProvider = class NfcBypassTouchNotifier extends StateNotifier { static const _prefNfcBypassTouch = 'prefNfcBypassTouch'; final SharedPreferences _prefs; + NfcBypassTouchNotifier(this._prefs) : super(_prefs.getBool(_prefNfcBypassTouch) ?? false); @@ -297,6 +299,7 @@ final androidNfcSilenceSoundsProvider = class NfcSilenceSoundsNotifier extends StateNotifier { static const _prefNfcSilenceSounds = 'prefNfcSilenceSounds'; final SharedPreferences _prefs; + NfcSilenceSoundsNotifier(this._prefs) : super(_prefs.getBool(_prefNfcSilenceSounds) ?? false); @@ -315,6 +318,7 @@ final androidUsbLaunchAppProvider = class UsbLaunchAppNotifier extends StateNotifier { static const _prefUsbOpenApp = 'prefUsbOpenApp'; final SharedPreferences _prefs; + UsbLaunchAppNotifier(this._prefs) : super(_prefs.getBool(_prefUsbOpenApp) ?? false); diff --git a/lib/android/window_state_provider.dart b/lib/android/window_state_provider.dart index 62788028..162cd713 100644 --- a/lib/android/window_state_provider.dart +++ b/lib/android/window_state_provider.dart @@ -58,7 +58,7 @@ class _WindowStateNotifier extends StateNotifier if (lifeCycleState == AppLifecycleState.resumed) { _log.debug('Reading nfc enabled value'); isNfcEnabled().then((value) => - _ref.read(androidNfcStateProvider.notifier).setNfcEnabled(value)); + _ref.read(androidNfcAdapterState.notifier).enable(value)); } } else { _log.debug('Ignoring appLifecycleStateChange'); diff --git a/lib/app/views/device_picker.dart b/lib/app/views/device_picker.dart index 126c90da..a1046f6a 100644 --- a/lib/app/views/device_picker.dart +++ b/lib/app/views/device_picker.dart @@ -71,7 +71,7 @@ class DevicePickerContent extends ConsumerWidget { Widget? androidNoKeyWidget; if (isAndroid && devices.isEmpty) { var hasNfcSupport = ref.watch(androidNfcSupportProvider); - var isNfcEnabled = ref.watch(androidNfcStateProvider); + var isNfcEnabled = ref.watch(androidNfcAdapterState); final subtitle = hasNfcSupport && isNfcEnabled ? l10n.l_insert_or_tap_yk : l10n.l_insert_yk; diff --git a/lib/app/views/main_page.dart b/lib/app/views/main_page.dart index e4cca258..ebf52c96 100755 --- a/lib/app/views/main_page.dart +++ b/lib/app/views/main_page.dart @@ -52,8 +52,8 @@ class MainPage extends ConsumerWidget { ); if (isAndroid) { - isNfcEnabled().then((value) => - ref.read(androidNfcStateProvider.notifier).setNfcEnabled(value)); + isNfcEnabled().then( + (value) => ref.read(androidNfcAdapterState.notifier).enable(value)); } // If the current device changes, we need to pop any open dialogs. @@ -98,7 +98,7 @@ class MainPage extends ConsumerWidget { if (deviceNode == null) { if (isAndroid) { var hasNfcSupport = ref.watch(androidNfcSupportProvider); - var isNfcEnabled = ref.watch(androidNfcStateProvider); + var isNfcEnabled = ref.watch(androidNfcAdapterState); return HomeMessagePage( centered: true, graphic: noKeyImage, diff --git a/lib/app/views/message_page_not_initialized.dart b/lib/app/views/message_page_not_initialized.dart index 229ed436..df72e53a 100644 --- a/lib/app/views/message_page_not_initialized.dart +++ b/lib/app/views/message_page_not_initialized.dart @@ -46,7 +46,7 @@ class MessagePageNotInitialized extends ConsumerWidget { if (isAndroid) { var hasNfcSupport = ref.watch(androidNfcSupportProvider); - var isNfcEnabled = ref.watch(androidNfcStateProvider); + var isNfcEnabled = ref.watch(androidNfcAdapterState); var isUsbYubiKey = ref.watch(attachedDevicesProvider).firstOrNull?.transport == Transport.usb;