@ledgerhq/device-transport-kit-react-native-hid 0.0.0-rn-hid-fixed-device-id-20250521093943 → 0.0.0-rn-hid-improvements-20250522101701
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -123,9 +123,10 @@ internal class DefaultAndroidUsbTransport(
|
|
|
123
123
|
"Device disconnected (sessionId=${deviceConnection.sessionId})"
|
|
124
124
|
)
|
|
125
125
|
)
|
|
126
|
-
deviceConnection.handleDeviceDisconnected()
|
|
127
126
|
usbConnections.remove(key)
|
|
128
127
|
usbConnectionsPendingReconnection.add(deviceConnection)
|
|
128
|
+
deviceConnection.handleDeviceDisconnected()
|
|
129
|
+
(deviceConnection.getApduSender() as AndroidUsbApduSender).release()
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
}
|
|
@@ -325,9 +326,10 @@ internal class DefaultAndroidUsbTransport(
|
|
|
325
326
|
val deviceConnection = DeviceConnection(
|
|
326
327
|
sessionId = sessionId,
|
|
327
328
|
deviceApduSender = apduSender,
|
|
328
|
-
isFatalSendApduFailure = { false },
|
|
329
|
+
isFatalSendApduFailure = { false },
|
|
329
330
|
reconnectionTimeoutDuration = 5.seconds,
|
|
330
331
|
onTerminated = {
|
|
332
|
+
(it.getApduSender() as AndroidUsbApduSender).release()
|
|
331
333
|
usbConnections.remove(sessionId)
|
|
332
334
|
usbConnectionsPendingReconnection.remove(it)
|
|
333
335
|
eventDispatcher.dispatch(TransportEvent.DeviceConnectionLost(sessionId))
|
|
@@ -22,7 +22,6 @@ import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogIn
|
|
|
22
22
|
import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
|
|
23
23
|
import com.ledger.devicesdk.shared.internal.transport.framer.to2BytesArray
|
|
24
24
|
import kotlinx.coroutines.CoroutineDispatcher
|
|
25
|
-
import kotlinx.coroutines.cancel
|
|
26
25
|
import kotlinx.coroutines.delay
|
|
27
26
|
import kotlinx.coroutines.launch
|
|
28
27
|
import kotlinx.coroutines.withContext
|
|
@@ -36,7 +35,7 @@ private const val DEFAULT_USB_INTERFACE = 0
|
|
|
36
35
|
|
|
37
36
|
internal class AndroidUsbApduSender(
|
|
38
37
|
override val dependencies: Dependencies,
|
|
39
|
-
|
|
38
|
+
usbManager: UsbManager,
|
|
40
39
|
private val framerService: FramerService,
|
|
41
40
|
private val request: UsbRequest,
|
|
42
41
|
private val ioDispatcher: CoroutineDispatcher,
|
|
@@ -47,49 +46,48 @@ internal class AndroidUsbApduSender(
|
|
|
47
46
|
val ledgerUsbDevice: LedgerUsbDevice,
|
|
48
47
|
)
|
|
49
48
|
|
|
49
|
+
private val usbDevice = dependencies.usbDevice
|
|
50
|
+
private val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
|
|
51
|
+
private val androidToUsbEndpoint =
|
|
52
|
+
usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
|
|
53
|
+
private val usbToAndroidEndpoint =
|
|
54
|
+
usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
|
|
55
|
+
private val usbConnection = usbManager.openDevice(usbDevice)
|
|
56
|
+
.apply { claimInterface(usbInterface, true) }
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
fun release() {
|
|
60
|
+
usbConnection.releaseInterface(usbInterface)
|
|
61
|
+
usbConnection.close()
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
override suspend fun send(apdu: ByteArray, abortTimeoutDuration: Duration): SendApduResult =
|
|
51
65
|
try {
|
|
52
|
-
val usbDevice = dependencies.usbDevice
|
|
53
66
|
withContext(context = ioDispatcher) {
|
|
54
|
-
val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
|
|
55
|
-
val androidToUsbEndpoint =
|
|
56
|
-
usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
|
|
57
|
-
val usbToAndroidEndpoint =
|
|
58
|
-
usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
|
|
59
|
-
val usbConnection = usbManager.openDevice(usbDevice)
|
|
60
|
-
.apply { claimInterface(usbInterface, true) }
|
|
61
67
|
|
|
62
68
|
val timeoutJob = launch {
|
|
63
69
|
delay(abortTimeoutDuration)
|
|
64
|
-
usbConnection.releaseInterface(usbInterface)
|
|
65
|
-
usbConnection.close()
|
|
66
70
|
throw SendApduTimeoutException
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
transmitApdu(
|
|
74
|
+
usbConnection = usbConnection,
|
|
75
|
+
androidToUsbEndpoint = androidToUsbEndpoint,
|
|
76
|
+
rawApdu = apdu,
|
|
77
|
+
)
|
|
70
78
|
|
|
71
|
-
|
|
79
|
+
val apduResponse =
|
|
80
|
+
receiveApdu(
|
|
72
81
|
usbConnection = usbConnection,
|
|
73
|
-
|
|
74
|
-
rawApdu = apdu,
|
|
82
|
+
usbToAndroidEndpoint = usbToAndroidEndpoint,
|
|
75
83
|
)
|
|
84
|
+
timeoutJob.cancel()
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
usbConnection = usbConnection,
|
|
80
|
-
usbToAndroidEndpoint = usbToAndroidEndpoint,
|
|
81
|
-
)
|
|
82
|
-
timeoutJob.cancel()
|
|
83
|
-
|
|
84
|
-
if (apduResponse.isEmpty()) {
|
|
85
|
-
return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return@withContext SendApduResult.Success(apdu = apduResponse)
|
|
89
|
-
} finally {
|
|
90
|
-
usbConnection.releaseInterface(usbInterface)
|
|
91
|
-
usbConnection.close()
|
|
86
|
+
if (apduResponse.isEmpty()) {
|
|
87
|
+
return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
|
|
92
88
|
}
|
|
89
|
+
|
|
90
|
+
return@withContext SendApduResult.Success(apdu = apduResponse)
|
|
93
91
|
}
|
|
94
92
|
} catch (e: SendApduTimeoutException) {
|
|
95
93
|
loggerService.log(
|
|
@@ -132,8 +130,8 @@ internal class AndroidUsbApduSender(
|
|
|
132
130
|
private fun receiveApdu(
|
|
133
131
|
usbConnection: UsbDeviceConnection,
|
|
134
132
|
usbToAndroidEndpoint: UsbEndpoint,
|
|
135
|
-
): ByteArray
|
|
136
|
-
if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
|
|
133
|
+
): ByteArray {
|
|
134
|
+
return if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
|
|
137
135
|
request.close()
|
|
138
136
|
byteArrayOf()
|
|
139
137
|
} else {
|
|
@@ -154,6 +152,7 @@ internal class AndroidUsbApduSender(
|
|
|
154
152
|
}
|
|
155
153
|
framerService.deserialize(mtu = USB_MTU, frames)
|
|
156
154
|
}
|
|
155
|
+
}
|
|
157
156
|
|
|
158
157
|
private fun UsbInterface.firstEndpointOrThrow(predicate: (Int) -> Boolean): UsbEndpoint {
|
|
159
158
|
for (endp in 0..this.endpointCount) {
|
|
@@ -169,7 +168,7 @@ internal class AndroidUsbApduSender(
|
|
|
169
168
|
private fun generateChannelId(): ByteArray =
|
|
170
169
|
Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
|
|
171
170
|
|
|
172
|
-
private data object SendApduTimeoutException: Exception() {
|
|
171
|
+
private data object SendApduTimeoutException : Exception() {
|
|
173
172
|
private fun readResolve(): Any = SendApduTimeoutException
|
|
174
173
|
}
|
|
175
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/device-transport-kit-react-native-hid",
|
|
3
|
-
"version": "0.0.0-rn-hid-
|
|
3
|
+
"version": "0.0.0-rn-hid-improvements-20250522101701",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"@types/uuid": "^10.0.0",
|
|
36
36
|
"react-native": "0.76.6",
|
|
37
37
|
"rxjs": "^7.8.2",
|
|
38
|
-
"@ledgerhq/device-management-kit": "0.0.0-rn-hid-
|
|
38
|
+
"@ledgerhq/device-management-kit": "0.0.0-rn-hid-improvements-20250522101701",
|
|
39
39
|
"@ledgerhq/eslint-config-dsdk": "0.0.2",
|
|
40
40
|
"@ledgerhq/ldmk-tool": "0.0.1",
|
|
41
|
-
"@ledgerhq/vitest-config-dmk": "0.0.0",
|
|
42
41
|
"@ledgerhq/prettier-config-dsdk": "0.0.2",
|
|
42
|
+
"@ledgerhq/vitest-config-dmk": "0.0.0",
|
|
43
43
|
"@ledgerhq/tsconfig-dsdk": "1.0.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"react-native": ">0.74.1",
|
|
47
47
|
"rxjs": "^7.8.2",
|
|
48
|
-
"@ledgerhq/device-management-kit": "0.0.0-rn-hid-
|
|
48
|
+
"@ledgerhq/device-management-kit": "0.0.0-rn-hid-improvements-20250522101701"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"prebuild": "rimraf lib",
|