Detect stale USB connections on resume
This commit is contained in:
@@ -328,7 +328,7 @@ class CredentialProviderActivity : AppCompatActivity() {
|
||||
registerReceiver(usbAttachReceiver, usbAttachFilter)
|
||||
}
|
||||
|
||||
if (currentTransport == null) {
|
||||
if (currentTransport?.isConnected != true || currentTransport is UsbTransport) {
|
||||
checkForUsbDevice()
|
||||
}
|
||||
}
|
||||
@@ -374,6 +374,19 @@ class CredentialProviderActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun checkForUsbDevice() {
|
||||
// Verify the existing USB connection is still usable
|
||||
val transport = currentTransport
|
||||
if (transport is UsbTransport) {
|
||||
try {
|
||||
transport.reclaimConnection()
|
||||
return // still good
|
||||
} catch (e: AuthnkeyError.NotConnected) {
|
||||
transport.close()
|
||||
currentTransport = null
|
||||
pinProtocol = null
|
||||
}
|
||||
}
|
||||
|
||||
val devices = usbManager.deviceList.values.filter { UsbTransport.isFidoDevice(it) }
|
||||
if (devices.isNotEmpty()) {
|
||||
val device = devices.first()
|
||||
|
||||
@@ -15,6 +15,14 @@ interface FidoTransport {
|
||||
val transportType: TransportType
|
||||
val isConnected: Boolean
|
||||
|
||||
/**
|
||||
* Verify that the transport connection is still active and usable.
|
||||
* Throws [AuthnkeyError.NotConnected] if the connection has been lost
|
||||
* (e.g. another app claimed the USB interface, or an NFC tag moved out of range).
|
||||
*/
|
||||
@Throws(AuthnkeyError.NotConnected::class)
|
||||
fun reclaimConnection()
|
||||
|
||||
@Throws(Exception::class)
|
||||
suspend fun sendCtapCommand(command: ByteArray): ByteArray
|
||||
|
||||
|
||||
@@ -208,7 +208,9 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
// Auto-connect to already-plugged USB FIDO devices
|
||||
checkForUsbDevice()
|
||||
if (currentTransport?.isConnected != true || currentTransport is UsbTransport) {
|
||||
checkForUsbDevice()
|
||||
}
|
||||
|
||||
// Check if started by USB device attachment
|
||||
if (intent.action == UsbManager.ACTION_USB_DEVICE_ATTACHED) {
|
||||
@@ -318,9 +320,19 @@ class MainActivity : AppCompatActivity() {
|
||||
* Only connects if there's exactly one device and we're not already connected.
|
||||
*/
|
||||
private fun checkForUsbDevice() {
|
||||
// Skip if already connected
|
||||
if (currentTransport?.isConnected == true) {
|
||||
return
|
||||
// Verify the existing USB connection is still usable
|
||||
val transport = currentTransport
|
||||
if (transport is UsbTransport) {
|
||||
try {
|
||||
transport.reclaimConnection()
|
||||
return // still good
|
||||
} catch (e: AuthnkeyError.NotConnected) {
|
||||
transport.close()
|
||||
currentTransport = null
|
||||
pinProtocol = null
|
||||
credentialManagement = null
|
||||
updateConnectionStatus()
|
||||
}
|
||||
}
|
||||
|
||||
val devices = usbManager.deviceList.values
|
||||
|
||||
@@ -19,6 +19,12 @@ class NfcTransport(private val isoDep: IsoDep) : FidoTransport {
|
||||
false
|
||||
}
|
||||
|
||||
override fun reclaimConnection() {
|
||||
if (!isConnected) {
|
||||
throw AuthnkeyError.NotConnected()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
if (!isoDep.isConnected) {
|
||||
isoDep.connect()
|
||||
|
||||
@@ -56,6 +56,12 @@ class UsbTransport(
|
||||
}
|
||||
}
|
||||
|
||||
override fun reclaimConnection() {
|
||||
if (!_isConnected || !connection.claimInterface(hidInterface, false)) {
|
||||
throw AuthnkeyError.NotConnected()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendCtapCommand(command: ByteArray): ByteArray = withContext(Dispatchers.IO) {
|
||||
// CTAPHID_CBOR command
|
||||
sendRaw(channelId, CMD_CBOR, command)
|
||||
|
||||
Reference in New Issue
Block a user