mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 18:22:39 +03:00
get SKY info from usbDevice
This commit is contained in:
parent
ab0e76d24c
commit
c32ab802ea
@ -24,8 +24,11 @@ suspend fun getDeviceInfo(device: YubiKeyDevice): Info {
|
|||||||
}.recoverCatching {
|
}.recoverCatching {
|
||||||
Log.d(OathManager.TAG, "OTP connection not available")
|
Log.d(OathManager.TAG, "OTP connection not available")
|
||||||
device.withConnection<FidoConnection, DeviceInfo> { DeviceUtil.readInfo(it, pid) }
|
device.withConnection<FidoConnection, DeviceInfo> { DeviceUtil.readInfo(it, pid) }
|
||||||
|
}.recoverCatching {
|
||||||
|
Log.d(OathManager.TAG, "FIDO connection not available")
|
||||||
|
return SkyHelper.getDeviceInfo(device)
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
Log.e(OathManager.TAG, "No connection available for getting device info")
|
Log.e(OathManager.TAG, "Failed to recognize device")
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
package com.yubico.authenticator.yubikit
|
||||||
|
|
||||||
|
import com.yubico.authenticator.device.Info
|
||||||
|
import com.yubico.authenticator.management.model
|
||||||
|
import com.yubico.yubikit.android.transport.usb.UsbYubiKeyDevice
|
||||||
|
import com.yubico.yubikit.core.Transport
|
||||||
|
import com.yubico.yubikit.core.UsbPid
|
||||||
|
import com.yubico.yubikit.core.Version
|
||||||
|
import com.yubico.yubikit.core.YubiKeyDevice
|
||||||
|
import com.yubico.yubikit.management.DeviceConfig
|
||||||
|
import com.yubico.yubikit.management.DeviceInfo
|
||||||
|
import com.yubico.yubikit.management.FormFactor
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class SkyHelper {
|
||||||
|
companion object {
|
||||||
|
private val VERSION_0 = Version(0, 0, 0)
|
||||||
|
private val VERSION_3 = Version(3, 0, 0)
|
||||||
|
private val VERSION_4 = Version(4, 0, 0)
|
||||||
|
private val VERSION_5 = Version(5, 0, 0)
|
||||||
|
private val VERSION_6 = Version(6, 0, 0)
|
||||||
|
|
||||||
|
private val USB_VERSION_STRING_PATTERN: Pattern =
|
||||||
|
Pattern.compile("\\b(\\d{1,3})\\.(\\d)(\\d+)\\b")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a [DeviceInfo] from USB Security YubiKey (SKY).
|
||||||
|
*
|
||||||
|
* Should be only used as last resort when all other DeviceInfo queries failed because
|
||||||
|
* the returned information might not be accurate.
|
||||||
|
*
|
||||||
|
* @param device YubiKeyDevice to get DeviceInfo for. Should be USB and SKY device
|
||||||
|
* @return [DeviceInfo] instance initialized with information from USB descriptors.
|
||||||
|
* @throws IllegalArgumentException if [device] is not instance of [UsbYubiKeyDevice] or
|
||||||
|
* if the USB device has wrong PID
|
||||||
|
*/
|
||||||
|
fun getDeviceInfo(device: YubiKeyDevice): Info {
|
||||||
|
if (device !is UsbYubiKeyDevice) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val pid = device.pid
|
||||||
|
|
||||||
|
if (pid !in listOf(UsbPid.YK4_FIDO, UsbPid.SKY_FIDO, UsbPid.NEO_FIDO)) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val usbVersion = validateVersionForPid(getVersionFromUsbDescriptor(device), pid)
|
||||||
|
|
||||||
|
// build DeviceInfo containing only USB product name and USB version
|
||||||
|
// we assume this is a Security Key based on the USB PID
|
||||||
|
return DeviceInfo(
|
||||||
|
DeviceConfig.Builder().enabledCapabilities(Transport.USB, 0).build(),
|
||||||
|
null,
|
||||||
|
usbVersion,
|
||||||
|
FormFactor.UNKNOWN,
|
||||||
|
mapOf(Transport.USB to 0),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
).model(device.usbDevice.productName ?: "YubiKey Security Key", false, pid.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to convert USB version to YubiKey version
|
||||||
|
private fun getVersionFromUsbDescriptor(device: UsbYubiKeyDevice): Version {
|
||||||
|
val version = device.usbDevice.version
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Version.parse(version)
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
val match = USB_VERSION_STRING_PATTERN.matcher(version)
|
||||||
|
if (match.find()) {
|
||||||
|
val major = match.group(1)?.toByte() ?: 0
|
||||||
|
val minor = match.group(2)?.toByte() ?: 0
|
||||||
|
val patch = match.group(3)?.toByte() ?: 0
|
||||||
|
return Version(major, minor, patch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VERSION_0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether usbVersion is in expected range defined by UsbPid
|
||||||
|
*
|
||||||
|
* @return original version or [Version(0,0,0)] indicating invalid/unknown version
|
||||||
|
*/
|
||||||
|
private fun validateVersionForPid(usbVersion: Version, pid: UsbPid): Version {
|
||||||
|
if (pid == UsbPid.NEO_FIDO && !usbVersion.inRange(VERSION_3, VERSION_4)) {
|
||||||
|
return VERSION_0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == UsbPid.SKY_FIDO && !usbVersion.inRange(VERSION_4, VERSION_5)) {
|
||||||
|
return VERSION_0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == UsbPid.YK4_FIDO && !usbVersion.inRange(VERSION_5, VERSION_6)) {
|
||||||
|
return VERSION_0
|
||||||
|
}
|
||||||
|
|
||||||
|
return usbVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check if this version is at least v1 and less than v2
|
||||||
|
* @return true if in range [v1,v2)
|
||||||
|
*/
|
||||||
|
private fun Version.inRange(v1: Version, v2: Version) : Boolean {
|
||||||
|
return this >= v1 && this < v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:yubico_authenticator/core/models.dart';
|
||||||
|
|
||||||
import '../../management/models.dart';
|
import '../../management/models.dart';
|
||||||
import '../models.dart';
|
import '../models.dart';
|
||||||
@ -9,7 +10,11 @@ String getDeviceInfoString(DeviceInfo info) {
|
|||||||
if (serial != null) {
|
if (serial != null) {
|
||||||
subtitle += 'S/N: $serial ';
|
subtitle += 'S/N: $serial ';
|
||||||
}
|
}
|
||||||
|
if (info.version.isAtLeast(1)) {
|
||||||
subtitle += 'F/W: ${info.version}';
|
subtitle += 'F/W: ${info.version}';
|
||||||
|
} else {
|
||||||
|
subtitle += 'Unknown type';
|
||||||
|
}
|
||||||
return subtitle;
|
return subtitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +29,7 @@ List<String> getDeviceMessages(DeviceNode? node, AsyncValue<YubiKeyData> data) {
|
|||||||
case 'unknown-device':
|
case 'unknown-device':
|
||||||
return ['Unrecognized device'];
|
return ['Unrecognized device'];
|
||||||
case 'device-inaccessible':
|
case 'device-inaccessible':
|
||||||
return ['Device inacessible'];
|
return ['Device inaccessible'];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user