mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 02:01:36 +03:00
remove nfc retries
This commit is contained in:
parent
e5e61648cf
commit
7b971f1472
@ -22,11 +22,13 @@ import com.yubico.yubikit.core.YubiKeyDevice
|
|||||||
* Provides behavior to run when a YubiKey is inserted/tapped for a specific view of the app.
|
* Provides behavior to run when a YubiKey is inserted/tapped for a specific view of the app.
|
||||||
*/
|
*/
|
||||||
abstract class AppContextManager {
|
abstract class AppContextManager {
|
||||||
abstract suspend fun processYubiKey(device: YubiKeyDevice)
|
abstract suspend fun processYubiKey(device: YubiKeyDevice): Boolean
|
||||||
|
|
||||||
open fun dispose() {}
|
open fun dispose() {}
|
||||||
|
|
||||||
open fun onPause() {}
|
open fun onPause() {}
|
||||||
|
|
||||||
|
open fun onError() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContextDisposedException : Exception()
|
class ContextDisposedException : Exception()
|
@ -321,6 +321,7 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
appMethodChannel.nfcStateChanged(NfcState.ONGOING)
|
appMethodChannel.nfcStateChanged(NfcState.ONGOING)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceManager.scpKeyParams = null
|
||||||
// If NFC and FIPS check for SCP11b key
|
// If NFC and FIPS check for SCP11b key
|
||||||
if (device.transport == Transport.NFC && deviceInfo.fipsCapable != 0) {
|
if (device.transport == Transport.NFC && deviceInfo.fipsCapable != 0) {
|
||||||
logger.debug("Checking for usable SCP11b key...")
|
logger.debug("Checking for usable SCP11b key...")
|
||||||
@ -340,6 +341,7 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.debug("Exception while getting scp keys: ", e)
|
logger.debug("Exception while getting scp keys: ", e)
|
||||||
|
contextManager?.onError()
|
||||||
if (device is NfcYubiKeyDevice) {
|
if (device is NfcYubiKeyDevice) {
|
||||||
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
||||||
}
|
}
|
||||||
@ -373,9 +375,12 @@ class MainActivity : FlutterFragmentActivity() {
|
|||||||
|
|
||||||
contextManager?.let {
|
contextManager?.let {
|
||||||
try {
|
try {
|
||||||
it.processYubiKey(device)
|
val requestHandled = it.processYubiKey(device)
|
||||||
if (!switchedContext && device is NfcYubiKeyDevice) {
|
if (requestHandled) {
|
||||||
appMethodChannel.nfcStateChanged(NfcState.SUCCESS)
|
appMethodChannel.nfcStateChanged(NfcState.SUCCESS)
|
||||||
|
}
|
||||||
|
if (!switchedContext && device is NfcYubiKeyDevice) {
|
||||||
|
|
||||||
device.remove {
|
device.remove {
|
||||||
appMethodChannel.nfcStateChanged(NfcState.IDLE)
|
appMethodChannel.nfcStateChanged(NfcState.IDLE)
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import com.yubico.yubikit.core.smartcard.scp.ScpKeyParams
|
|||||||
import com.yubico.yubikit.management.Capability
|
import com.yubico.yubikit.management.Capability
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
interface DeviceListener {
|
interface DeviceListener {
|
||||||
// a USB device is connected
|
// a USB device is connected
|
||||||
@ -174,7 +175,6 @@ class DeviceManager(
|
|||||||
|
|
||||||
fun setDeviceInfo(deviceInfo: Info?) {
|
fun setDeviceInfo(deviceInfo: Info?) {
|
||||||
appViewModel.setDeviceInfo(deviceInfo)
|
appViewModel.setDeviceInfo(deviceInfo)
|
||||||
this.scpKeyParams = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isUsbKeyConnected(): Boolean {
|
fun isUsbKeyConnected(): Boolean {
|
||||||
@ -189,16 +189,12 @@ class DeviceManager(
|
|||||||
suspend fun <T> withKey(
|
suspend fun <T> withKey(
|
||||||
onUsb: suspend (UsbYubiKeyDevice) -> T,
|
onUsb: suspend (UsbYubiKeyDevice) -> T,
|
||||||
onNfc: suspend () -> com.yubico.yubikit.core.util.Result<T, Throwable>,
|
onNfc: suspend () -> com.yubico.yubikit.core.util.Result<T, Throwable>,
|
||||||
onCancelled: () -> Unit,
|
onCancelled: () -> Unit
|
||||||
retryOnNfcFailure: Boolean
|
|
||||||
): T =
|
): T =
|
||||||
appViewModel.connectedYubiKey.value?.let {
|
appViewModel.connectedYubiKey.value?.let {
|
||||||
onUsb(it)
|
onUsb(it)
|
||||||
} ?: if (retryOnNfcFailure == true) {
|
} ?: onNfc(onNfc, onCancelled)
|
||||||
onNfcWithRetries(onNfc, onCancelled)
|
|
||||||
} else {
|
|
||||||
onNfc(onNfc, onCancelled)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun <T> onNfc(
|
private suspend fun <T> onNfc(
|
||||||
onNfc: suspend () -> com.yubico.yubikit.core.util.Result<T, Throwable>,
|
onNfc: suspend () -> com.yubico.yubikit.core.util.Result<T, Throwable>,
|
||||||
@ -210,42 +206,12 @@ class DeviceManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return onNfc.invoke().value
|
return onNfc.invoke().value.also {
|
||||||
|
appMethodChannel.nfcStateChanged(NfcState.SUCCESS)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun <T> onNfcWithRetries(
|
|
||||||
onNfc: suspend () -> com.yubico.yubikit.core.util.Result<T, Throwable>,
|
|
||||||
onCancelled: () -> Unit
|
|
||||||
): T {
|
|
||||||
|
|
||||||
nfcOverlayManager.show {
|
|
||||||
logger.debug("NFC action with retries was cancelled")
|
|
||||||
onCancelled.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
return onNfc.invoke().value
|
|
||||||
} catch (e: Exception) {
|
|
||||||
|
|
||||||
logger.debug("NFC action failed, asking to try again. Failure: ", e)
|
|
||||||
if (e is CancellationException) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e is ContextDisposedException) {
|
|
||||||
// the key does not have the needed context anymore
|
|
||||||
// we cannot continue
|
|
||||||
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
appMethodChannel.nfcStateChanged(NfcState.FAILURE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -30,17 +30,19 @@ import kotlin.coroutines.suspendCoroutine
|
|||||||
|
|
||||||
class FidoConnectionHelper(private val deviceManager: DeviceManager) {
|
class FidoConnectionHelper(private val deviceManager: DeviceManager) {
|
||||||
private var pendingAction: FidoAction? = null
|
private var pendingAction: FidoAction? = null
|
||||||
private var deviceInfoTimer: TimerTask? = null
|
|
||||||
|
|
||||||
fun invokePending(fidoSession: YubiKitFidoSession) {
|
fun invokePending(fidoSession: YubiKitFidoSession): Boolean {
|
||||||
|
var requestHandled = true
|
||||||
pendingAction?.let { action ->
|
pendingAction?.let { action ->
|
||||||
action.invoke(Result.success(fidoSession))
|
|
||||||
pendingAction = null
|
pendingAction = null
|
||||||
|
// it is the pending action who handles this request
|
||||||
|
requestHandled = false
|
||||||
|
action.invoke(Result.success(fidoSession))
|
||||||
}
|
}
|
||||||
|
return requestHandled
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancelPending() {
|
fun cancelPending() {
|
||||||
deviceInfoTimer?.cancel()
|
|
||||||
pendingAction?.let { action ->
|
pendingAction?.let { action ->
|
||||||
action.invoke(Result.failure(CancellationException()))
|
action.invoke(Result.failure(CancellationException()))
|
||||||
pendingAction = null
|
pendingAction = null
|
||||||
@ -49,7 +51,6 @@ class FidoConnectionHelper(private val deviceManager: DeviceManager) {
|
|||||||
|
|
||||||
suspend fun <T> useSession(
|
suspend fun <T> useSession(
|
||||||
updateDeviceInfo: Boolean = false,
|
updateDeviceInfo: Boolean = false,
|
||||||
retryOnNfcFailure: Boolean = true,
|
|
||||||
block: (YubiKitFidoSession) -> T
|
block: (YubiKitFidoSession) -> T
|
||||||
): T {
|
): T {
|
||||||
FidoManager.updateDeviceInfo.set(updateDeviceInfo)
|
FidoManager.updateDeviceInfo.set(updateDeviceInfo)
|
||||||
@ -59,8 +60,7 @@ class FidoConnectionHelper(private val deviceManager: DeviceManager) {
|
|||||||
onCancelled = {
|
onCancelled = {
|
||||||
pendingAction?.invoke(Result.failure(CancellationException()))
|
pendingAction?.invoke(Result.failure(CancellationException()))
|
||||||
pendingAction = null
|
pendingAction = null
|
||||||
},
|
}
|
||||||
retryOnNfcFailure = retryOnNfcFailure
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +127,6 @@ class FidoManager(
|
|||||||
pinStore
|
pinStore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
pinRetries = null
|
pinRetries = null
|
||||||
|
|
||||||
@ -176,6 +174,12 @@ class FidoManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onError() {
|
||||||
|
super.onError()
|
||||||
|
logger.debug("Cancel any pending action because of upstream error")
|
||||||
|
connectionHelper.cancelPending()
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
super.dispose()
|
super.dispose()
|
||||||
deviceManager.removeDeviceListener(this)
|
deviceManager.removeDeviceListener(this)
|
||||||
@ -186,15 +190,16 @@ class FidoManager(
|
|||||||
coroutineScope.cancel()
|
coroutineScope.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun processYubiKey(device: YubiKeyDevice) {
|
override suspend fun processYubiKey(device: YubiKeyDevice): Boolean {
|
||||||
|
var requestHandled = true
|
||||||
try {
|
try {
|
||||||
if (device.supportsConnection(FidoConnection::class.java)) {
|
if (device.supportsConnection(FidoConnection::class.java)) {
|
||||||
device.withConnection<FidoConnection, Unit> { connection ->
|
device.withConnection<FidoConnection, Unit> { connection ->
|
||||||
processYubiKey(connection, device)
|
requestHandled = processYubiKey(connection, device)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
device.withConnection<SmartCardConnection, Unit> { connection ->
|
device.withConnection<SmartCardConnection, Unit> { connection ->
|
||||||
processYubiKey(connection, device)
|
requestHandled = processYubiKey(connection, device)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,10 +212,14 @@ class FidoManager(
|
|||||||
|
|
||||||
// Clear any cached FIDO state
|
// Clear any cached FIDO state
|
||||||
fidoViewModel.clearSessionState()
|
fidoViewModel.clearSessionState()
|
||||||
}
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processYubiKey(connection: YubiKeyConnection, device: YubiKeyDevice) {
|
return requestHandled
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processYubiKey(connection: YubiKeyConnection, device: YubiKeyDevice): Boolean {
|
||||||
|
var requestHandled = true
|
||||||
val fidoSession =
|
val fidoSession =
|
||||||
if (connection is FidoConnection) {
|
if (connection is FidoConnection) {
|
||||||
YubiKitFidoSession(connection)
|
YubiKitFidoSession(connection)
|
||||||
@ -229,7 +238,7 @@ class FidoManager(
|
|||||||
val sameDevice = currentSession == previousSession
|
val sameDevice = currentSession == previousSession
|
||||||
|
|
||||||
if (device is NfcYubiKeyDevice && (sameDevice || resetHelper.inProgress)) {
|
if (device is NfcYubiKeyDevice && (sameDevice || resetHelper.inProgress)) {
|
||||||
connectionHelper.invokePending(fidoSession)
|
requestHandled = connectionHelper.invokePending(fidoSession)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (!sameDevice) {
|
if (!sameDevice) {
|
||||||
@ -253,6 +262,8 @@ class FidoManager(
|
|||||||
Session(infoData, pinStore.hasPin(), pinRetries)
|
Session(infoData, pinStore.hasPin(), pinRetries)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return requestHandled
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPinPermissionsCM(fidoSession: YubiKitFidoSession): Int {
|
private fun getPinPermissionsCM(fidoSession: YubiKitFidoSession): Int {
|
||||||
|
@ -39,8 +39,7 @@ class ManagementConnectionHelper(
|
|||||||
onCancelled = {
|
onCancelled = {
|
||||||
action?.invoke(Result.failure(CancellationException()))
|
action?.invoke(Result.failure(CancellationException()))
|
||||||
action = null
|
action = null
|
||||||
},
|
}
|
||||||
retryOnNfcFailure = false
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun <T> useSessionUsb(
|
private suspend fun <T> useSessionUsb(
|
||||||
|
@ -110,6 +110,15 @@ class OathManager(
|
|||||||
private val updateDeviceInfo = AtomicBoolean(false)
|
private val updateDeviceInfo = AtomicBoolean(false)
|
||||||
private var deviceInfoTimer: TimerTask? = null
|
private var deviceInfoTimer: TimerTask? = null
|
||||||
|
|
||||||
|
override fun onError() {
|
||||||
|
super.onError()
|
||||||
|
logger.debug("Cancel any pending action because of upstream error")
|
||||||
|
pendingAction?.let { action ->
|
||||||
|
action.invoke(Result.failure(CancellationException()))
|
||||||
|
pendingAction = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
deviceInfoTimer?.cancel()
|
deviceInfoTimer?.cancel()
|
||||||
// cancel any pending actions, except for addToAny
|
// cancel any pending actions, except for addToAny
|
||||||
@ -217,7 +226,8 @@ class OathManager(
|
|||||||
coroutineScope.cancel()
|
coroutineScope.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun processYubiKey(device: YubiKeyDevice) {
|
override suspend fun processYubiKey(device: YubiKeyDevice): Boolean {
|
||||||
|
var requestHandled = true
|
||||||
try {
|
try {
|
||||||
device.withConnection<SmartCardConnection, Unit> { connection ->
|
device.withConnection<SmartCardConnection, Unit> { connection ->
|
||||||
val session = getOathSession(connection)
|
val session = getOathSession(connection)
|
||||||
@ -227,6 +237,8 @@ class OathManager(
|
|||||||
if (pendingAction != null) {
|
if (pendingAction != null) {
|
||||||
pendingAction?.let { action ->
|
pendingAction?.let { action ->
|
||||||
pendingAction = null
|
pendingAction = null
|
||||||
|
// it is the pending action who handles this request
|
||||||
|
requestHandled = false
|
||||||
action.invoke(Result.success(session))
|
action.invoke(Result.success(session))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -235,7 +247,7 @@ class OathManager(
|
|||||||
try {
|
try {
|
||||||
oathViewModel.updateCredentials(calculateOathCodes(session))
|
oathViewModel.updateCredentials(calculateOathCodes(session))
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
logger.error("Failed to refresh codes", error)
|
logger.error("Failed to refresh codes: ", error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,7 +275,9 @@ class OathManager(
|
|||||||
if (addToAny) {
|
if (addToAny) {
|
||||||
// Special "add to any YubiKey" action, process
|
// Special "add to any YubiKey" action, process
|
||||||
addToAny = false
|
addToAny = false
|
||||||
|
requestHandled = false
|
||||||
action.invoke(Result.success(session))
|
action.invoke(Result.success(session))
|
||||||
|
requestHandled = true
|
||||||
} else {
|
} else {
|
||||||
// Awaiting an action for a different device? Fail it and stop processing.
|
// Awaiting an action for a different device? Fail it and stop processing.
|
||||||
action.invoke(Result.failure(IllegalStateException("Wrong deviceId")))
|
action.invoke(Result.failure(IllegalStateException("Wrong deviceId")))
|
||||||
@ -305,8 +319,17 @@ class OathManager(
|
|||||||
logger.error("Failed to connect to CCID: ", e)
|
logger.error("Failed to connect to CCID: ", e)
|
||||||
// Clear any cached OATH state
|
// Clear any cached OATH state
|
||||||
oathViewModel.clearSession()
|
oathViewModel.clearSession()
|
||||||
|
// Remove any pending action
|
||||||
|
pendingAction?.let { action ->
|
||||||
|
logger.error("Cancelling pending action")
|
||||||
|
pendingAction = null
|
||||||
|
action.invoke(Result.failure(CancellationException()))
|
||||||
|
}
|
||||||
|
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return requestHandled
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun addAccountToAny(
|
private suspend fun addAccountToAny(
|
||||||
@ -316,7 +339,7 @@ class OathManager(
|
|||||||
val credentialData: CredentialData =
|
val credentialData: CredentialData =
|
||||||
CredentialData.parseUri(URI.create(uri))
|
CredentialData.parseUri(URI.create(uri))
|
||||||
addToAny = true
|
addToAny = true
|
||||||
return useOathSession(retryOnNfcFailure = false) { session ->
|
return useOathSession { session ->
|
||||||
// We need to check for duplicates here since we haven't yet read the credentials
|
// We need to check for duplicates here since we haven't yet read the credentials
|
||||||
if (session.credentials.any { it.id.contentEquals(credentialData.id) }) {
|
if (session.credentials.any { it.id.contentEquals(credentialData.id) }) {
|
||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
@ -346,7 +369,7 @@ class OathManager(
|
|||||||
logger.trace("Adding following accounts: {}", uris)
|
logger.trace("Adding following accounts: {}", uris)
|
||||||
|
|
||||||
addToAny = true
|
addToAny = true
|
||||||
return useOathSession(retryOnNfcFailure = false) { session ->
|
return useOathSession { session ->
|
||||||
var successCount = 0
|
var successCount = 0
|
||||||
for (index in uris.indices) {
|
for (index in uris.indices) {
|
||||||
|
|
||||||
@ -398,7 +421,16 @@ class OathManager(
|
|||||||
val remembered = keyManager.isRemembered(it.deviceId)
|
val remembered = keyManager.isRemembered(it.deviceId)
|
||||||
if (unlocked) {
|
if (unlocked) {
|
||||||
oathViewModel.setSessionState(Session(it, remembered))
|
oathViewModel.setSessionState(Session(it, remembered))
|
||||||
|
|
||||||
|
try {
|
||||||
oathViewModel.updateCredentials(calculateOathCodes(it))
|
oathViewModel.updateCredentials(calculateOathCodes(it))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// after unlocking there was problem getting the codes
|
||||||
|
// to avoid incomplete session, just reset it so that the user has to
|
||||||
|
// unlock it again
|
||||||
|
oathViewModel.clearSession()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonSerializer.encodeToString(mapOf("unlocked" to unlocked, "remembered" to remembered))
|
jsonSerializer.encodeToString(mapOf("unlocked" to unlocked, "remembered" to remembered))
|
||||||
@ -682,7 +714,6 @@ class OathManager(
|
|||||||
private suspend fun <T> useOathSession(
|
private suspend fun <T> useOathSession(
|
||||||
unlock: Boolean = true,
|
unlock: Boolean = true,
|
||||||
updateDeviceInfo: Boolean = false,
|
updateDeviceInfo: Boolean = false,
|
||||||
retryOnNfcFailure: Boolean = true,
|
|
||||||
block: (YubiKitOathSession) -> T
|
block: (YubiKitOathSession) -> T
|
||||||
): T {
|
): T {
|
||||||
// callers can decide whether the session should be unlocked first
|
// callers can decide whether the session should be unlocked first
|
||||||
@ -695,8 +726,7 @@ class OathManager(
|
|||||||
onCancelled = {
|
onCancelled = {
|
||||||
pendingAction?.invoke(Result.failure(CancellationException()))
|
pendingAction?.invoke(Result.failure(CancellationException()))
|
||||||
pendingAction = null
|
pendingAction = null
|
||||||
},
|
}
|
||||||
retryOnNfcFailure = retryOnNfcFailure
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,7 +752,6 @@ class OathManager(
|
|||||||
block.invoke(it.value)
|
block.invoke(it.value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// here the coroutine is suspended and waits till pendingAction is
|
// here the coroutine is suspended and waits till pendingAction is
|
||||||
// invoked - the pending action result will resume this coroutine
|
// invoked - the pending action result will resume this coroutine
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import 'views/nfc_content_widget.dart';
|
|||||||
import 'views/nfc_overlay_icons.dart';
|
import 'views/nfc_overlay_icons.dart';
|
||||||
import 'views/nfc_overlay_widget.dart';
|
import 'views/nfc_overlay_widget.dart';
|
||||||
|
|
||||||
final _log = Logger('android.tap_request_dialog');
|
final _log = Logger('android.nfc_overlay');
|
||||||
const _channel = MethodChannel('com.yubico.authenticator.channel.nfc_overlay');
|
const _channel = MethodChannel('com.yubico.authenticator.channel.nfc_overlay');
|
||||||
|
|
||||||
final nfcOverlay =
|
final nfcOverlay =
|
||||||
@ -41,6 +41,7 @@ class _NfcOverlayNotifier extends Notifier<int> {
|
|||||||
@override
|
@override
|
||||||
int build() {
|
int build() {
|
||||||
ref.listen(androidNfcState, (previous, current) {
|
ref.listen(androidNfcState, (previous, current) {
|
||||||
|
_log.debug('Received nfc state: $current');
|
||||||
processingViewTimeout?.cancel();
|
processingViewTimeout?.cancel();
|
||||||
final notifier = ref.read(nfcEventNotifier.notifier);
|
final notifier = ref.read(nfcEventNotifier.notifier);
|
||||||
|
|
||||||
@ -62,6 +63,8 @@ class _NfcOverlayNotifier extends Notifier<int> {
|
|||||||
break;
|
break;
|
||||||
case NfcState.failure:
|
case NfcState.failure:
|
||||||
notifier.send(showFailed());
|
notifier.send(showFailed());
|
||||||
|
notifier
|
||||||
|
.send(const NfcHideViewEvent(delay: Duration(milliseconds: 800)));
|
||||||
break;
|
break;
|
||||||
case NfcState.disabled:
|
case NfcState.disabled:
|
||||||
_log.debug('Received state: disabled');
|
_log.debug('Received state: disabled');
|
||||||
@ -125,7 +128,7 @@ class _NfcOverlayNotifier extends Notifier<int> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NfcEvent showFailed() {
|
NfcEvent showFailed() {
|
||||||
ref.read(nfcOverlayWidgetProperties.notifier).update(hasCloseButton: true);
|
ref.read(nfcOverlayWidgetProperties.notifier).update(hasCloseButton: false);
|
||||||
return NfcSetViewEvent(
|
return NfcSetViewEvent(
|
||||||
child: NfcContentWidget(
|
child: NfcContentWidget(
|
||||||
title: l10n.s_nfc_ready_to_scan,
|
title: l10n.s_nfc_ready_to_scan,
|
||||||
|
@ -59,19 +59,11 @@ class MainPage extends ConsumerWidget {
|
|||||||
// If the current device changes, we need to pop any open dialogs.
|
// If the current device changes, we need to pop any open dialogs.
|
||||||
ref.listen<AsyncValue<YubiKeyData>>(currentDeviceDataProvider,
|
ref.listen<AsyncValue<YubiKeyData>>(currentDeviceDataProvider,
|
||||||
(prev, next) {
|
(prev, next) {
|
||||||
var canPop = true;
|
final serial = next.value?.info.serial;
|
||||||
if ((next.value != null) && (prev?.value != null)) {
|
if (serial != null && serial == prev?.value?.info.serial) {
|
||||||
// if there is change only in fipsApproved, don't pop anything
|
return;
|
||||||
var nextInfo = next.value!.info;
|
|
||||||
var prevInfo = prev!.value!.info;
|
|
||||||
|
|
||||||
canPop =
|
|
||||||
prevInfo.copyWith(fipsApproved: nextInfo.fipsApproved) != nextInfo;
|
|
||||||
} else if (next.hasValue && (prev != null && prev.isLoading)) {
|
|
||||||
canPop = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canPop) {
|
|
||||||
Navigator.of(context).popUntil((route) {
|
Navigator.of(context).popUntil((route) {
|
||||||
return route.isFirst ||
|
return route.isFirst ||
|
||||||
[
|
[
|
||||||
@ -85,7 +77,6 @@ class MainPage extends ConsumerWidget {
|
|||||||
'android_qr_scanner_view',
|
'android_qr_scanner_view',
|
||||||
].contains(route.settings.name);
|
].contains(route.settings.name);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final deviceNode = ref.watch(currentDeviceProvider);
|
final deviceNode = ref.watch(currentDeviceProvider);
|
||||||
|
Loading…
Reference in New Issue
Block a user