mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 10:11:52 +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 {
|
||||
Log.d(OathManager.TAG, "OTP connection not available")
|
||||
device.withConnection<FidoConnection, DeviceInfo> { DeviceUtil.readInfo(it, pid) }
|
||||
}.recoverCatching {
|
||||
Log.d(OathManager.TAG, "FIDO connection not available")
|
||||
return SkyHelper.getDeviceInfo(device)
|
||||
}.getOrElse {
|
||||
Log.e(OathManager.TAG, "No connection available for getting device info")
|
||||
Log.e(OathManager.TAG, "Failed to recognize device")
|
||||
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:yubico_authenticator/core/models.dart';
|
||||
|
||||
import '../../management/models.dart';
|
||||
import '../models.dart';
|
||||
@ -9,7 +10,11 @@ String getDeviceInfoString(DeviceInfo info) {
|
||||
if (serial != null) {
|
||||
subtitle += 'S/N: $serial ';
|
||||
}
|
||||
subtitle += 'F/W: ${info.version}';
|
||||
if (info.version.isAtLeast(1)) {
|
||||
subtitle += 'F/W: ${info.version}';
|
||||
} else {
|
||||
subtitle += 'Unknown type';
|
||||
}
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
@ -24,7 +29,7 @@ List<String> getDeviceMessages(DeviceNode? node, AsyncValue<YubiKeyData> data) {
|
||||
case 'unknown-device':
|
||||
return ['Unrecognized device'];
|
||||
case 'device-inaccessible':
|
||||
return ['Device inacessible'];
|
||||
return ['Device inaccessible'];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user