@ledgerhq/device-transport-kit-react-native-hid 0.0.0-develop-20250904001204 → 0.0.0-e2e-speculos-20250904125723

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.
Files changed (54) hide show
  1. package/android/src/main/kotlin/com/ledger/androidtransporthid/TransportHidModule.kt +3 -12
  2. package/android/src/main/kotlin/com/ledger/androidtransporthid/bridge/serialization.kt +0 -2
  3. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/DefaultAndroidUsbTransport.kt +23 -85
  4. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/connection/AndroidUsbApduSender.kt +29 -70
  5. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceApduSender.kt +1 -2
  6. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnection.kt +4 -5
  7. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachine.kt +33 -103
  8. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/SendApduResult.kt +0 -4
  9. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/connection/InternalConnectedDevice.kt +1 -1
  10. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachineTest.kt +46 -189
  11. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionTest.kt +5 -9
  12. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js +1 -1
  13. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js.map +3 -3
  14. package/lib/cjs/api/bridge/mapper.js +1 -1
  15. package/lib/cjs/api/bridge/mapper.js.map +2 -2
  16. package/lib/cjs/api/bridge/mapper.test.js +1 -1
  17. package/lib/cjs/api/bridge/mapper.test.js.map +2 -2
  18. package/lib/cjs/api/bridge/types.js +1 -1
  19. package/lib/cjs/api/bridge/types.js.map +1 -1
  20. package/lib/cjs/api/transport/Errors.js +1 -1
  21. package/lib/cjs/api/transport/Errors.js.map +3 -3
  22. package/lib/cjs/api/transport/NativeModuleWrapper.js +1 -1
  23. package/lib/cjs/api/transport/NativeModuleWrapper.js.map +1 -1
  24. package/lib/cjs/api/transport/RNHidTransport.js +1 -1
  25. package/lib/cjs/api/transport/RNHidTransport.js.map +3 -3
  26. package/lib/cjs/api/transport/RNHidTransport.test.js +1 -1
  27. package/lib/cjs/api/transport/RNHidTransport.test.js.map +2 -2
  28. package/lib/cjs/package.json +1 -1
  29. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js +1 -1
  30. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js.map +3 -3
  31. package/lib/esm/api/bridge/mapper.js +1 -1
  32. package/lib/esm/api/bridge/mapper.js.map +3 -3
  33. package/lib/esm/api/bridge/mapper.test.js +1 -1
  34. package/lib/esm/api/bridge/mapper.test.js.map +3 -3
  35. package/lib/esm/api/bridge/types.js.map +1 -1
  36. package/lib/esm/api/transport/Errors.js +1 -1
  37. package/lib/esm/api/transport/Errors.js.map +3 -3
  38. package/lib/esm/api/transport/RNHidTransport.js +1 -1
  39. package/lib/esm/api/transport/RNHidTransport.js.map +3 -3
  40. package/lib/esm/api/transport/RNHidTransport.test.js +1 -1
  41. package/lib/esm/api/transport/RNHidTransport.test.js.map +3 -3
  42. package/lib/esm/package.json +1 -1
  43. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts +1 -1
  44. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts.map +1 -1
  45. package/lib/types/api/bridge/mapper.d.ts.map +1 -1
  46. package/lib/types/api/bridge/types.d.ts +2 -2
  47. package/lib/types/api/bridge/types.d.ts.map +1 -1
  48. package/lib/types/api/transport/Errors.d.ts +1 -1
  49. package/lib/types/api/transport/Errors.d.ts.map +1 -1
  50. package/lib/types/api/transport/NativeModuleWrapper.d.ts +1 -1
  51. package/lib/types/api/transport/NativeModuleWrapper.d.ts.map +1 -1
  52. package/lib/types/api/transport/RNHidTransport.d.ts.map +1 -1
  53. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  54. package/package.json +9 -9
@@ -2,9 +2,9 @@ package com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnecti
2
2
 
3
3
  import com.ledger.devicesdk.shared.api.apdu.SendApduFailureReason
4
4
  import com.ledger.devicesdk.shared.api.apdu.SendApduResult
5
- import com.ledger.devicesdk.shared.api.utils.fromHexStringToBytesOrThrow
6
5
  import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
7
6
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleDebugLogInfo
7
+ import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleInfoLogInfo
8
8
  import kotlinx.coroutines.CoroutineDispatcher
9
9
  import kotlinx.coroutines.CoroutineScope
10
10
  import kotlinx.coroutines.Job
@@ -12,7 +12,7 @@ import kotlinx.coroutines.launch
12
12
  import kotlin.time.Duration
13
13
 
14
14
  internal class DeviceConnectionStateMachine(
15
- private val sendApduFn: (apdu: ByteArray, abortTimeoutDuration: Duration) -> Unit,
15
+ private val sendApduFn: (apdu: ByteArray) -> Unit,
16
16
  private val onTerminated: () -> Unit,
17
17
  private val isFatalSendApduFailure: (SendApduResult.Failure) -> Boolean,
18
18
  private val reconnectionTimeoutDuration: Duration,
@@ -26,29 +26,10 @@ internal class DeviceConnectionStateMachine(
26
26
  fun getState() = state
27
27
 
28
28
  private fun pushState(newState: State) {
29
-
30
- val currentState = state
31
-
32
- /* STATE EXIT EFFECTS */
33
- if (newState != currentState) {
34
- when (currentState) {
35
- is State.WaitingForDisconnection -> {
36
- currentState.requestContent.resultCallback(currentState.result)
37
- }
38
- else -> {}
39
- }
40
- }
41
-
42
- /* STATE ENTRY EFFECTS */
43
29
  when (newState) {
44
30
  is State.Connected -> {}
45
31
  is State.SendingApdu -> {
46
- sendApduFn(newState.requestContent.apdu, newState.requestContent.abortTimeoutDuration)
47
- }
48
-
49
- is State.WaitingForDisconnection -> {
50
- // TODO: send getAppAndVersion
51
- sendApduFn ("b0010000".fromHexStringToBytesOrThrow(), Duration.INFINITE)
32
+ sendApduFn(newState.requestContent.apdu)
52
33
  }
53
34
 
54
35
  is State.WaitingForReconnection -> {
@@ -61,16 +42,11 @@ internal class DeviceConnectionStateMachine(
61
42
  }
62
43
  }
63
44
  this.state = newState
64
- loggerService.log(buildSimpleDebugLogInfo("DeviceConnectionStateMachine", "-> New state: $newState"))
65
45
  }
66
46
 
67
47
  private fun handleEvent(event: Event) {
68
- val logMessage = """
69
- -> Event received: $event
70
- In state: $state
71
- """.trimIndent()
72
- loggerService.log(buildSimpleDebugLogInfo("DeviceConnectionStateMachine", logMessage))
73
- when (val currentState = state) {
48
+ val currentState = state
49
+ when (currentState) {
74
50
  is State.Connected -> {
75
51
  when (event) {
76
52
  is Event.SendApduRequested -> {
@@ -95,27 +71,31 @@ internal class DeviceConnectionStateMachine(
95
71
  when (event) {
96
72
  is Event.ApduResultReceived -> {
97
73
  when (event.result) {
98
- is SendApduResult.Success -> {
99
- // check if last 2 bytes of APDU are [0x90,OxO0]
100
- val apdu = event.result.apdu
101
-
102
-
103
- if (isSuccessApdu(apdu) && currentState.requestContent.triggersDisconnection) {
104
- pushState(State.WaitingForDisconnection(requestContent = currentState.requestContent, result = event.result))
74
+ is SendApduResult.Failure -> {
75
+ if (isFatalSendApduFailure(event.result)) {
76
+ pushState(State.Terminated)
105
77
  } else {
106
78
  pushState(State.Connected)
107
- currentState.requestContent.resultCallback(event.result)
108
79
  }
109
80
  }
110
- is SendApduResult.Failure -> {
111
- if (isFatalSendApduFailure(event.result)) {
112
- pushState(State.Terminated)
81
+
82
+ is SendApduResult.Success -> {
83
+ // check if last 2 bytes of APDU are [0x90,OxO0]
84
+ val apdu = event.result.apdu
85
+ val apduSize = apdu.size
86
+ val isSuccessApdu =
87
+ apdu.size >= 2 &&
88
+ apdu[apduSize - 2] == 0x90.toByte() &&
89
+ apdu[apduSize - 1] == 0x00.toByte()
90
+
91
+ if (isSuccessApdu && currentState.requestContent.triggersDisconnection) {
92
+ pushState(State.WaitingForReconnection)
113
93
  } else {
114
94
  pushState(State.Connected)
115
95
  }
116
- currentState.requestContent.resultCallback(event.result)
117
96
  }
118
97
  }
98
+ currentState.requestContent.resultCallback(event.result)
119
99
  }
120
100
 
121
101
  is Event.CloseConnectionRequested -> {
@@ -150,42 +130,6 @@ internal class DeviceConnectionStateMachine(
150
130
  }
151
131
  }
152
132
 
153
- is State.WaitingForDisconnection -> {
154
- when (event) {
155
- is Event.ApduResultReceived -> {
156
- when (event.result) {
157
- is SendApduResult.Success -> {
158
- val apdu = event.result.apdu
159
- if (isSendApduBusyError(apdu)) {
160
- pushState(state) // Loop on same state, will trigger a new send of GetAppAndVersion (entry effect)
161
- } else {
162
- pushState(State.Connected)
163
- }
164
- }
165
- is SendApduResult.Failure -> {
166
- pushState(State.WaitingForReconnection)
167
- }
168
- }
169
- }
170
- is Event.SendApduRequested -> {
171
- event.requestContent.resultCallback(
172
- SendApduResult.Failure(
173
- SendApduFailureReason.DeviceBusy
174
- )
175
- )
176
- }
177
- is Event.DeviceDisconnected -> {
178
- pushState(State.WaitingForReconnection)
179
- }
180
- is Event.CloseConnectionRequested -> {
181
- pushState(State.Terminated)
182
- }
183
- else -> {
184
- onError(Exception("Unhandled event: $event in state: $currentState"))
185
- }
186
- }
187
- }
188
-
189
133
  is State.WaitingForReconnection -> {
190
134
  when (event) {
191
135
  is Event.DeviceConnected -> {
@@ -290,24 +234,13 @@ internal class DeviceConnectionStateMachine(
290
234
  onError(Exception("Unhandled event: $event in state: $currentState"))
291
235
  }
292
236
  }
293
- }
294
-
295
- private fun isSuccessApdu(apdu: ByteArray): Boolean {
296
- val apduSize = apdu.size
297
- return apduSize >= 2 &&
298
- apdu[apduSize - 2] == 0x90.toByte() &&
299
- apdu[apduSize - 1] == 0x00.toByte()
300
- }
301
-
302
- private fun isSendApduBusyError(apdu: ByteArray): Boolean {
303
- val apduSize = apdu.size
304
- return apduSize >= 2 &&
305
- apdu[apduSize - 2] == 0x66.toByte() &&
306
- apdu[apduSize - 1] == 0x01.toByte()
307
- }
308
-
309
- private fun sendGetAppAndVersionApdu() {
310
- sendApduFn("b0010000".fromHexStringToBytesOrThrow(), Duration.INFINITE)
237
+ val logMessage = """
238
+ Received event:
239
+ In state: $currentState
240
+ -> Event: $event
241
+ -> New state: $state
242
+ """.trimIndent()
243
+ loggerService.log(buildSimpleDebugLogInfo("DeviceConnectionStateMachine", logMessage))
311
244
  }
312
245
 
313
246
  private var timeoutJob: Job? = null
@@ -324,30 +257,29 @@ internal class DeviceConnectionStateMachine(
324
257
  timeoutJob = null
325
258
  }
326
259
 
327
- fun requestSendApdu(requestContent: SendApduRequestContent) {
260
+ public fun requestSendApdu(requestContent: SendApduRequestContent) {
328
261
  handleEvent(Event.SendApduRequested(requestContent))
329
262
  }
330
263
 
331
- fun requestCloseConnection() {
264
+ public fun requestCloseConnection() {
332
265
  handleEvent(Event.CloseConnectionRequested)
333
266
  }
334
267
 
335
- fun handleApduResult(result: SendApduResult) {
268
+ public fun handleApduResult(result: SendApduResult) {
336
269
  handleEvent(Event.ApduResultReceived(result))
337
270
  }
338
271
 
339
- fun handleDeviceConnected() {
272
+ public fun handleDeviceConnected() {
340
273
  handleEvent(Event.DeviceConnected)
341
274
  }
342
275
 
343
- fun handleDeviceDisconnected() {
276
+ public fun handleDeviceDisconnected() {
344
277
  handleEvent(Event.DeviceDisconnected)
345
278
  }
346
279
 
347
280
  data class SendApduRequestContent(
348
281
  val apdu: ByteArray,
349
282
  val triggersDisconnection: Boolean,
350
- val abortTimeoutDuration: Duration,
351
283
  val resultCallback: (SendApduResult) -> Unit
352
284
  )
353
285
 
@@ -374,8 +306,6 @@ internal class DeviceConnectionStateMachine(
374
306
 
375
307
  data object WaitingForReconnection : State()
376
308
 
377
- data class WaitingForDisconnection(val requestContent: SendApduRequestContent, val result: SendApduResult): State()
378
-
379
309
  data class WaitingForReconnectionWithQueuedApdu(val requestContent: SendApduRequestContent) :
380
310
  State()
381
311
 
@@ -44,8 +44,4 @@ public sealed class SendApduFailureReason {
44
44
  public data object DeviceDisconnected : SendApduFailureReason()
45
45
 
46
46
  public data object Unknown : SendApduFailureReason()
47
-
48
- public data object AbortTimeout : SendApduFailureReason()
49
-
50
- public data object EmptyResponse : SendApduFailureReason()
51
47
  }
@@ -9,5 +9,5 @@ internal data class InternalConnectedDevice(
9
9
  val name: String,
10
10
  val ledgerDevice: LedgerDevice,
11
11
  val connectivity: ConnectivityType,
12
- val sendApduFn: suspend (apdu: ByteArray, triggersDisconnection: Boolean, abortTimeoutDuration: kotlin.time.Duration) -> SendApduResult,
12
+ val sendApduFn: suspend (ByteArray) -> SendApduResult,
13
13
  )