@ledgerhq/react-native-hw-transport-ble 6.35.5 → 6.35.6-nightly.1

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @ledgerhq/react-native-hw-transport-ble@6.35.5 build /home/runner/work/ledger-live/ledger-live/libs/ledgerjs/packages/react-native-hw-transport-ble
2
+ > @ledgerhq/react-native-hw-transport-ble@6.35.6-nightly.0 build /home/runner/work/ledger-live/ledger-live/libs/ledgerjs/packages/react-native-hw-transport-ble
3
3
  > tsc && tsc -m esnext --moduleResolution bundler --outDir lib-es
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @ledgerhq/react-native-hw-transport-ble
2
2
 
3
+ ## 6.35.6-nightly.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`c1a4bfd`](https://github.com/LedgerHQ/ledger-live/commit/c1a4bfd34b46c6b6587d247673cadb3c078deb1d)]:
8
+ - @ledgerhq/devices@8.7.0-nightly.1
9
+ - @ledgerhq/hw-transport@6.31.13-nightly.1
10
+
11
+ ## 6.35.6-nightly.0
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [[`759064d`](https://github.com/LedgerHQ/ledger-live/commit/759064d4815c636af2d73ba548a85b4f53e7b491)]:
16
+ - @ledgerhq/errors@6.27.0-nightly.0
17
+ - @ledgerhq/devices@8.6.2-nightly.0
18
+ - @ledgerhq/hw-transport@6.31.13-nightly.0
19
+
3
20
  ## 6.35.5
4
21
 
5
22
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/react-native-hw-transport-ble",
3
- "version": "6.35.5",
3
+ "version": "6.35.6-nightly.1",
4
4
  "description": "Ledger Hardware Wallet Bluetooth BLE transport for React Native",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -28,9 +28,9 @@
28
28
  "react-native-ble-plx": "3.4.0",
29
29
  "rxjs": "^7.8.1",
30
30
  "uuid": "^9.0.1",
31
- "@ledgerhq/devices": "8.6.1",
32
- "@ledgerhq/errors": "^6.26.0",
33
- "@ledgerhq/hw-transport": "^6.31.12",
31
+ "@ledgerhq/devices": "8.7.0-nightly.1",
32
+ "@ledgerhq/errors": "^6.27.0-nightly.0",
33
+ "@ledgerhq/hw-transport": "6.31.13-nightly.1",
34
34
  "@ledgerhq/logs": "^6.13.0"
35
35
  },
36
36
  "gitHead": "dd0dea64b58e5a9125c8a422dcffd29e5ef6abec",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BleTransport.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BleTransport.test.d.ts","sourceRoot":"","sources":["../src/BleTransport.test.ts"],"names":[],"mappings":""}
@@ -1,343 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const errors_1 = require("@ledgerhq/errors");
7
- const BleTransport_1 = __importDefault(require("../src/BleTransport"));
8
- const rxjs_1 = require("rxjs");
9
- let mockNoResponseFromDevice = false;
10
- const mockCancelTransaction = jest.fn();
11
- let mockNegotiatedMtu;
12
- /**
13
- * It is essential to mock the BLE component of a BLE transport to verify
14
- * the reliability of the connect/reconnect/disconnect logic, which is decoupled
15
- * from the managing logic of live-common or any other implementation.
16
- * Although it may seem trivial, such an approach is necessary to ensure
17
- * that the implementation is robust and dependable.
18
- *
19
- * To this end, a mocked react-native-ble-plx has been developed specifically
20
- * to cover test cases. It should be noted that this mock is not comprehensive
21
- * and may require further refinement to meet all requirements.
22
- */
23
- jest.mock("react-native-ble-plx", () => {
24
- class BleError {
25
- iosErrorCode;
26
- reason;
27
- constructor(iosErrorCode, reason) {
28
- this.iosErrorCode = iosErrorCode;
29
- this.reason = reason;
30
- }
31
- }
32
- // Set of callbacks that we can trigger from our tests.
33
- const callbacks = {};
34
- return {
35
- BleErrorCode: {
36
- ScanStartFailed: 0,
37
- },
38
- BleError,
39
- ConnectionPriority: {
40
- Balanced: 0,
41
- High: 1,
42
- LowPower: 2,
43
- },
44
- BleManager: function () {
45
- const dynamicProps = {
46
- isConnected: true,
47
- };
48
- return {
49
- onStateChange: callback => {
50
- setTimeout(() => callback("PoweredOn"), 500);
51
- return new rxjs_1.Subscription();
52
- },
53
- cancelDeviceConnection: async () => {
54
- dynamicProps.isConnected = false;
55
- callbacks?.onDisconnected(null);
56
- },
57
- devices: () => [],
58
- connectedDevices: () => [],
59
- connectToDevice: () => {
60
- dynamicProps.isConnected = true;
61
- return {
62
- isConnectable: null,
63
- serviceData: null,
64
- overflowServiceUUIDs: null,
65
- txPowerLevel: null,
66
- serviceUUIDs: null,
67
- rssi: null,
68
- mtu: 0,
69
- name: "Ledger Stax 2783",
70
- localName: null,
71
- id: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
72
- manufacturerData: null,
73
- solicitedServiceUUIDs: null,
74
- requestConnectionPriority: async () => {
75
- return null; // Should return self.
76
- },
77
- isConnected: () => {
78
- return dynamicProps.isConnected;
79
- },
80
- onDisconnected: callback => {
81
- callbacks["onDisconnected"] = () => callback(null); // Disconnect without an error
82
- return new rxjs_1.Subscription();
83
- },
84
- discoverAllServicesAndCharacteristics: () => { },
85
- characteristicsForService: uuid => {
86
- if (uuid === "13d63400-2c97-6004-0000-4c6564676572") {
87
- return [
88
- {
89
- // Device responses
90
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
91
- isIndicatable: false,
92
- isNotifiable: true,
93
- isWritableWithoutResponse: false,
94
- isWritableWithResponse: false,
95
- serviceID: 105553179758272,
96
- isReadable: false,
97
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
98
- isNotifying: false,
99
- value: "BQAAACMzIAAECTEuMC4wLXJjOQTuAAALBDUuMTUEMC4zNQEAAQCQAA==",
100
- id: 105553399124864,
101
- uuid: "13d63400-2c97-6004-0001-4c6564676572",
102
- monitor: cb => {
103
- callbacks["onDeviceResponse"] = cb;
104
- return new rxjs_1.Subscription();
105
- },
106
- },
107
- {
108
- // Write
109
- isNotifying: false,
110
- value: null,
111
- isIndicatable: false,
112
- id: 105553399131872,
113
- uuid: "13d63400-2c97-6004-0002-4c6564676572",
114
- isReadable: false,
115
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
116
- serviceID: 105553179758272,
117
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
118
- isWritableWithoutResponse: false,
119
- isWritableWithResponse: true,
120
- isNotifiable: false,
121
- },
122
- {
123
- // Used for write without response
124
- isWritableWithoutResponse: true,
125
- isWritableWithResponse: false,
126
- isNotifiable: false,
127
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
128
- isReadable: false,
129
- value: null,
130
- isNotifying: false,
131
- isIndicatable: false,
132
- id: 105553399132064,
133
- uuid: "13d63400-2c97-6004-0003-4c6564676572",
134
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
135
- serviceID: 105553179758272,
136
- writeWithoutResponse: async (raw) => {
137
- // No response are sent back from the device (using `onDeviceResponse`)
138
- // Imitates the case where the device is still connected but does not responds
139
- // when saving the newly confirmed seed.
140
- if (mockNoResponseFromDevice) {
141
- return;
142
- }
143
- if (!dynamicProps.isConnected)
144
- throw new BleError(22, "Device is not connected");
145
- const hex = Buffer.from(raw, "base64").toString("hex");
146
- let value;
147
- switch (hex) {
148
- // MTU handshake
149
- case "0800000000":
150
- value = mockNegotiatedMtu;
151
- break;
152
- // getAppAndVersion - returning BOLOS on 1.0.0-rc9
153
- case "0500000005b010000000":
154
- value = Buffer.from("05000000130105424f4c4f5309312e302e302d7263399000", "hex");
155
- break;
156
- // just used for a non resolving apdu
157
- case "0500000005b020000000":
158
- setTimeout(() => {
159
- callbacks?.onDeviceResponse(null, {
160
- value: Buffer.from("05000000029000", "hex"),
161
- });
162
- }, 600);
163
- return; // Called after a delay to give time for the disconnect
164
- default:
165
- throw new Error("some generic failure");
166
- }
167
- // Introduce some logic to actually respond.
168
- callbacks?.onDeviceResponse(null, {
169
- value,
170
- });
171
- },
172
- },
173
- ];
174
- }
175
- throw Error("Generic mocked error");
176
- },
177
- };
178
- },
179
- cancelTransaction: mockCancelTransaction,
180
- };
181
- },
182
- };
183
- });
184
- describe("BleTransport connectivity test coverage", () => {
185
- const deviceId = "20EDD96F-7430-6E33-AB22-DD8AAB857CD4";
186
- beforeEach(() => {
187
- mockNoResponseFromDevice = false;
188
- // MTU of 153 bytes
189
- mockNegotiatedMtu = Buffer.from("080000000099", "hex");
190
- mockCancelTransaction.mockClear();
191
- });
192
- describe("Device available and already paired", () => {
193
- it("should find the device, connect, negotiate MTU", async () => {
194
- const transport = await BleTransport_1.default.open(deviceId);
195
- expect(transport.device.isConnected()).toBe(true);
196
- });
197
- it("should be disconnectable, and cleanup", async () => {
198
- const transport = await BleTransport_1.default.open(deviceId);
199
- await BleTransport_1.default.disconnectDevice(deviceId);
200
- expect(transport.isConnected).toBe(false);
201
- });
202
- it("should disconnect in 500ms (5s default) after calling close", async () => {
203
- const transport = await BleTransport_1.default.open(deviceId);
204
- expect(transport.isConnected).toBe(true);
205
- BleTransport_1.default.disconnectTimeoutMs = 500;
206
- await transport.close();
207
- // Expect the timeout for disconnection to be set
208
- expect(transport.disconnectTimeout).not.toBe(undefined);
209
- let resolve;
210
- transport.on("disconnect", () => {
211
- resolve();
212
- });
213
- return await new Promise((_resolve, _reject) => {
214
- resolve = _resolve;
215
- });
216
- });
217
- it("should cancel disconnect if new connection is made", async () => {
218
- const transport = await BleTransport_1.default.open(deviceId);
219
- expect(transport.isConnected).toBe(true);
220
- BleTransport_1.default.disconnectTimeoutMs = 500;
221
- await transport.close();
222
- // Expect the timeout for disconnection to be set
223
- expect(transport.disconnectTimeout).not.toBe(undefined);
224
- // Nb due to the different environments, the timeout behaves differently here
225
- // and I can't check against a number for it to be cleared or not.
226
- expect(transport.disconnectTimeout._destroyed).toBe(false);
227
- await BleTransport_1.default.open(deviceId);
228
- expect(transport.disconnectTimeout._destroyed).toBe(true);
229
- });
230
- it("should cancel disconnect if already disconnected", async () => {
231
- const transport = await BleTransport_1.default.open(deviceId);
232
- expect(transport.isConnected).toBe(true);
233
- BleTransport_1.default.disconnectTimeoutMs = 500;
234
- await transport.close();
235
- // Expect the timeout for disconnection to be set
236
- expect(transport.disconnectTimeout).not.toBe(undefined);
237
- // Nb due to the different environments, the timeout behaves differently here
238
- // and I can't check against a number for it to be cleared or not.
239
- expect(transport.disconnectTimeout._destroyed).toBe(false);
240
- await BleTransport_1.default.disconnectDevice(deviceId);
241
- expect(transport.disconnectTimeout._destroyed).toBe(true);
242
- });
243
- describe("When the message to exchange fits in 1 frame", () => {
244
- it("should handle exchanges if all goes well", async () => {
245
- const transport = await BleTransport_1.default.open(deviceId);
246
- expect(transport.isConnected).toBe(true);
247
- const response = await transport.exchange(Buffer.from("b010000000", "hex"));
248
- expect(response.toString("hex")).toBe("0105424f4c4f5309312e302e302d7263399000");
249
- });
250
- it("should throw on exchanges if disconnected", async () => {
251
- const transport = await BleTransport_1.default.open(deviceId);
252
- expect(transport.isConnected).toBe(true);
253
- await BleTransport_1.default.disconnectDevice(deviceId);
254
- await expect(transport.exchange(Buffer.from("b010000000", "hex"))).rejects.toThrow(); // More specific errors some day.
255
- });
256
- describe("And when an abort timeout is set", () => {
257
- const abortTimeoutMs = 1000;
258
- it("should throw an error and cancel the transaction if the abort timeout was reached", done => {
259
- const rxjsScheduler = new rxjs_1.VirtualTimeScheduler();
260
- async function asyncFn() {
261
- const transport = await BleTransport_1.default.open(deviceId);
262
- expect(transport.isConnected).toBe(true);
263
- // Once we got the transport (MTU exchanged), we stop the communication
264
- mockNoResponseFromDevice = true;
265
- transport
266
- .exchange(Buffer.from("b010000000", "hex"), { abortTimeoutMs })
267
- .then(() => {
268
- done("It should not succeed");
269
- })
270
- .catch(error => {
271
- expect(error).toBeInstanceOf(errors_1.TransportExchangeTimeoutError);
272
- expect(mockCancelTransaction).toHaveBeenCalledTimes(1);
273
- done();
274
- });
275
- rxjsScheduler.flush();
276
- }
277
- asyncFn();
278
- });
279
- });
280
- });
281
- // Multi-frames message response is not handled by our current mocked react-native-ble-plx
282
- // The logic of encoding a message into several frames is tested directly with unit tests on ledgerhq/devices/lib/ble/sendAPDU
283
- describe("When the message to exchange needs more than 1 frame", () => {
284
- beforeEach(async () => {
285
- // Triggering a disconnection and clearing the transport cache
286
- await BleTransport_1.default.disconnectDevice(deviceId);
287
- // MTU of 25 bytes
288
- mockNegotiatedMtu = Buffer.from("080000000019", "hex");
289
- });
290
- afterEach(async () => {
291
- // Triggering a disconnection and clearing the transport cache
292
- await BleTransport_1.default.disconnectDevice(deviceId);
293
- });
294
- describe("And when an abort timeout is set", () => {
295
- const abortTimeoutMs = 1000;
296
- it("should throw an error and cancel the transactions of all operations if the abort timeout was reached", done => {
297
- const rxjsScheduler = new rxjs_1.VirtualTimeScheduler();
298
- async function asyncFn() {
299
- const transport = await BleTransport_1.default.open(deviceId);
300
- expect(transport.isConnected).toBe(true);
301
- // Once we got the transport (MTU exchanged), we stop the communication
302
- mockNoResponseFromDevice = true;
303
- // Imaginary APDU that will create an encoded message longer than MTU = 25 bytes
304
- transport
305
- .exchange(Buffer.from("b010000000b010000000b010000000b010000000b010000000", "hex"), {
306
- abortTimeoutMs,
307
- })
308
- .then(() => {
309
- done("It should not succeed");
310
- })
311
- .catch(error => {
312
- expect(error).toBeInstanceOf(errors_1.TransportExchangeTimeoutError);
313
- expect(mockCancelTransaction).toHaveBeenCalledTimes(2);
314
- done();
315
- });
316
- rxjsScheduler.flush();
317
- }
318
- asyncFn();
319
- });
320
- });
321
- });
322
- it("should disconnect if close is called, even if pending response", done => {
323
- // This is actually a very important test, if we have an ongoing apdu response,
324
- // as in, the device never replied, but we expressed the intention of disconnecting
325
- // we will give it a few seconds and then disconnect regardless. Otherwise we fall
326
- // in the never ending await trap.
327
- async function asyncFn() {
328
- const transport = await BleTransport_1.default.open(deviceId);
329
- expect(transport.isConnected).toBe(true);
330
- transport.exchange(Buffer.from("b020000000", "hex"));
331
- BleTransport_1.default.disconnectTimeoutMs = 500;
332
- transport.on("disconnect", () => {
333
- done(); // If this is never called, then we're still waiting.
334
- });
335
- await transport.close();
336
- // Expect the timeout for disconnection to be set
337
- expect(transport.disconnectTimeout).not.toBe(undefined);
338
- }
339
- asyncFn();
340
- });
341
- });
342
- });
343
- //# sourceMappingURL=BleTransport.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BleTransport.test.js","sourceRoot":"","sources":["../src/BleTransport.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BleTransport.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BleTransport.test.d.ts","sourceRoot":"","sources":["../src/BleTransport.test.ts"],"names":[],"mappings":""}
@@ -1,338 +0,0 @@
1
- import { TransportExchangeTimeoutError } from "@ledgerhq/errors";
2
- import BleTransport from "../src/BleTransport";
3
- import { Subscription, VirtualTimeScheduler } from "rxjs";
4
- let mockNoResponseFromDevice = false;
5
- const mockCancelTransaction = jest.fn();
6
- let mockNegotiatedMtu;
7
- /**
8
- * It is essential to mock the BLE component of a BLE transport to verify
9
- * the reliability of the connect/reconnect/disconnect logic, which is decoupled
10
- * from the managing logic of live-common or any other implementation.
11
- * Although it may seem trivial, such an approach is necessary to ensure
12
- * that the implementation is robust and dependable.
13
- *
14
- * To this end, a mocked react-native-ble-plx has been developed specifically
15
- * to cover test cases. It should be noted that this mock is not comprehensive
16
- * and may require further refinement to meet all requirements.
17
- */
18
- jest.mock("react-native-ble-plx", () => {
19
- class BleError {
20
- iosErrorCode;
21
- reason;
22
- constructor(iosErrorCode, reason) {
23
- this.iosErrorCode = iosErrorCode;
24
- this.reason = reason;
25
- }
26
- }
27
- // Set of callbacks that we can trigger from our tests.
28
- const callbacks = {};
29
- return {
30
- BleErrorCode: {
31
- ScanStartFailed: 0,
32
- },
33
- BleError,
34
- ConnectionPriority: {
35
- Balanced: 0,
36
- High: 1,
37
- LowPower: 2,
38
- },
39
- BleManager: function () {
40
- const dynamicProps = {
41
- isConnected: true,
42
- };
43
- return {
44
- onStateChange: callback => {
45
- setTimeout(() => callback("PoweredOn"), 500);
46
- return new Subscription();
47
- },
48
- cancelDeviceConnection: async () => {
49
- dynamicProps.isConnected = false;
50
- callbacks?.onDisconnected(null);
51
- },
52
- devices: () => [],
53
- connectedDevices: () => [],
54
- connectToDevice: () => {
55
- dynamicProps.isConnected = true;
56
- return {
57
- isConnectable: null,
58
- serviceData: null,
59
- overflowServiceUUIDs: null,
60
- txPowerLevel: null,
61
- serviceUUIDs: null,
62
- rssi: null,
63
- mtu: 0,
64
- name: "Ledger Stax 2783",
65
- localName: null,
66
- id: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
67
- manufacturerData: null,
68
- solicitedServiceUUIDs: null,
69
- requestConnectionPriority: async () => {
70
- return null; // Should return self.
71
- },
72
- isConnected: () => {
73
- return dynamicProps.isConnected;
74
- },
75
- onDisconnected: callback => {
76
- callbacks["onDisconnected"] = () => callback(null); // Disconnect without an error
77
- return new Subscription();
78
- },
79
- discoverAllServicesAndCharacteristics: () => { },
80
- characteristicsForService: uuid => {
81
- if (uuid === "13d63400-2c97-6004-0000-4c6564676572") {
82
- return [
83
- {
84
- // Device responses
85
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
86
- isIndicatable: false,
87
- isNotifiable: true,
88
- isWritableWithoutResponse: false,
89
- isWritableWithResponse: false,
90
- serviceID: 105553179758272,
91
- isReadable: false,
92
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
93
- isNotifying: false,
94
- value: "BQAAACMzIAAECTEuMC4wLXJjOQTuAAALBDUuMTUEMC4zNQEAAQCQAA==",
95
- id: 105553399124864,
96
- uuid: "13d63400-2c97-6004-0001-4c6564676572",
97
- monitor: cb => {
98
- callbacks["onDeviceResponse"] = cb;
99
- return new Subscription();
100
- },
101
- },
102
- {
103
- // Write
104
- isNotifying: false,
105
- value: null,
106
- isIndicatable: false,
107
- id: 105553399131872,
108
- uuid: "13d63400-2c97-6004-0002-4c6564676572",
109
- isReadable: false,
110
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
111
- serviceID: 105553179758272,
112
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
113
- isWritableWithoutResponse: false,
114
- isWritableWithResponse: true,
115
- isNotifiable: false,
116
- },
117
- {
118
- // Used for write without response
119
- isWritableWithoutResponse: true,
120
- isWritableWithResponse: false,
121
- isNotifiable: false,
122
- deviceID: "20EDD96F-7430-6E33-AB22-DD8AAB857CD4",
123
- isReadable: false,
124
- value: null,
125
- isNotifying: false,
126
- isIndicatable: false,
127
- id: 105553399132064,
128
- uuid: "13d63400-2c97-6004-0003-4c6564676572",
129
- serviceUUID: "13d63400-2c97-6004-0000-4c6564676572",
130
- serviceID: 105553179758272,
131
- writeWithoutResponse: async (raw) => {
132
- // No response are sent back from the device (using `onDeviceResponse`)
133
- // Imitates the case where the device is still connected but does not responds
134
- // when saving the newly confirmed seed.
135
- if (mockNoResponseFromDevice) {
136
- return;
137
- }
138
- if (!dynamicProps.isConnected)
139
- throw new BleError(22, "Device is not connected");
140
- const hex = Buffer.from(raw, "base64").toString("hex");
141
- let value;
142
- switch (hex) {
143
- // MTU handshake
144
- case "0800000000":
145
- value = mockNegotiatedMtu;
146
- break;
147
- // getAppAndVersion - returning BOLOS on 1.0.0-rc9
148
- case "0500000005b010000000":
149
- value = Buffer.from("05000000130105424f4c4f5309312e302e302d7263399000", "hex");
150
- break;
151
- // just used for a non resolving apdu
152
- case "0500000005b020000000":
153
- setTimeout(() => {
154
- callbacks?.onDeviceResponse(null, {
155
- value: Buffer.from("05000000029000", "hex"),
156
- });
157
- }, 600);
158
- return; // Called after a delay to give time for the disconnect
159
- default:
160
- throw new Error("some generic failure");
161
- }
162
- // Introduce some logic to actually respond.
163
- callbacks?.onDeviceResponse(null, {
164
- value,
165
- });
166
- },
167
- },
168
- ];
169
- }
170
- throw Error("Generic mocked error");
171
- },
172
- };
173
- },
174
- cancelTransaction: mockCancelTransaction,
175
- };
176
- },
177
- };
178
- });
179
- describe("BleTransport connectivity test coverage", () => {
180
- const deviceId = "20EDD96F-7430-6E33-AB22-DD8AAB857CD4";
181
- beforeEach(() => {
182
- mockNoResponseFromDevice = false;
183
- // MTU of 153 bytes
184
- mockNegotiatedMtu = Buffer.from("080000000099", "hex");
185
- mockCancelTransaction.mockClear();
186
- });
187
- describe("Device available and already paired", () => {
188
- it("should find the device, connect, negotiate MTU", async () => {
189
- const transport = await BleTransport.open(deviceId);
190
- expect(transport.device.isConnected()).toBe(true);
191
- });
192
- it("should be disconnectable, and cleanup", async () => {
193
- const transport = await BleTransport.open(deviceId);
194
- await BleTransport.disconnectDevice(deviceId);
195
- expect(transport.isConnected).toBe(false);
196
- });
197
- it("should disconnect in 500ms (5s default) after calling close", async () => {
198
- const transport = await BleTransport.open(deviceId);
199
- expect(transport.isConnected).toBe(true);
200
- BleTransport.disconnectTimeoutMs = 500;
201
- await transport.close();
202
- // Expect the timeout for disconnection to be set
203
- expect(transport.disconnectTimeout).not.toBe(undefined);
204
- let resolve;
205
- transport.on("disconnect", () => {
206
- resolve();
207
- });
208
- return await new Promise((_resolve, _reject) => {
209
- resolve = _resolve;
210
- });
211
- });
212
- it("should cancel disconnect if new connection is made", async () => {
213
- const transport = await BleTransport.open(deviceId);
214
- expect(transport.isConnected).toBe(true);
215
- BleTransport.disconnectTimeoutMs = 500;
216
- await transport.close();
217
- // Expect the timeout for disconnection to be set
218
- expect(transport.disconnectTimeout).not.toBe(undefined);
219
- // Nb due to the different environments, the timeout behaves differently here
220
- // and I can't check against a number for it to be cleared or not.
221
- expect(transport.disconnectTimeout._destroyed).toBe(false);
222
- await BleTransport.open(deviceId);
223
- expect(transport.disconnectTimeout._destroyed).toBe(true);
224
- });
225
- it("should cancel disconnect if already disconnected", async () => {
226
- const transport = await BleTransport.open(deviceId);
227
- expect(transport.isConnected).toBe(true);
228
- BleTransport.disconnectTimeoutMs = 500;
229
- await transport.close();
230
- // Expect the timeout for disconnection to be set
231
- expect(transport.disconnectTimeout).not.toBe(undefined);
232
- // Nb due to the different environments, the timeout behaves differently here
233
- // and I can't check against a number for it to be cleared or not.
234
- expect(transport.disconnectTimeout._destroyed).toBe(false);
235
- await BleTransport.disconnectDevice(deviceId);
236
- expect(transport.disconnectTimeout._destroyed).toBe(true);
237
- });
238
- describe("When the message to exchange fits in 1 frame", () => {
239
- it("should handle exchanges if all goes well", async () => {
240
- const transport = await BleTransport.open(deviceId);
241
- expect(transport.isConnected).toBe(true);
242
- const response = await transport.exchange(Buffer.from("b010000000", "hex"));
243
- expect(response.toString("hex")).toBe("0105424f4c4f5309312e302e302d7263399000");
244
- });
245
- it("should throw on exchanges if disconnected", async () => {
246
- const transport = await BleTransport.open(deviceId);
247
- expect(transport.isConnected).toBe(true);
248
- await BleTransport.disconnectDevice(deviceId);
249
- await expect(transport.exchange(Buffer.from("b010000000", "hex"))).rejects.toThrow(); // More specific errors some day.
250
- });
251
- describe("And when an abort timeout is set", () => {
252
- const abortTimeoutMs = 1000;
253
- it("should throw an error and cancel the transaction if the abort timeout was reached", done => {
254
- const rxjsScheduler = new VirtualTimeScheduler();
255
- async function asyncFn() {
256
- const transport = await BleTransport.open(deviceId);
257
- expect(transport.isConnected).toBe(true);
258
- // Once we got the transport (MTU exchanged), we stop the communication
259
- mockNoResponseFromDevice = true;
260
- transport
261
- .exchange(Buffer.from("b010000000", "hex"), { abortTimeoutMs })
262
- .then(() => {
263
- done("It should not succeed");
264
- })
265
- .catch(error => {
266
- expect(error).toBeInstanceOf(TransportExchangeTimeoutError);
267
- expect(mockCancelTransaction).toHaveBeenCalledTimes(1);
268
- done();
269
- });
270
- rxjsScheduler.flush();
271
- }
272
- asyncFn();
273
- });
274
- });
275
- });
276
- // Multi-frames message response is not handled by our current mocked react-native-ble-plx
277
- // The logic of encoding a message into several frames is tested directly with unit tests on ledgerhq/devices/lib/ble/sendAPDU
278
- describe("When the message to exchange needs more than 1 frame", () => {
279
- beforeEach(async () => {
280
- // Triggering a disconnection and clearing the transport cache
281
- await BleTransport.disconnectDevice(deviceId);
282
- // MTU of 25 bytes
283
- mockNegotiatedMtu = Buffer.from("080000000019", "hex");
284
- });
285
- afterEach(async () => {
286
- // Triggering a disconnection and clearing the transport cache
287
- await BleTransport.disconnectDevice(deviceId);
288
- });
289
- describe("And when an abort timeout is set", () => {
290
- const abortTimeoutMs = 1000;
291
- it("should throw an error and cancel the transactions of all operations if the abort timeout was reached", done => {
292
- const rxjsScheduler = new VirtualTimeScheduler();
293
- async function asyncFn() {
294
- const transport = await BleTransport.open(deviceId);
295
- expect(transport.isConnected).toBe(true);
296
- // Once we got the transport (MTU exchanged), we stop the communication
297
- mockNoResponseFromDevice = true;
298
- // Imaginary APDU that will create an encoded message longer than MTU = 25 bytes
299
- transport
300
- .exchange(Buffer.from("b010000000b010000000b010000000b010000000b010000000", "hex"), {
301
- abortTimeoutMs,
302
- })
303
- .then(() => {
304
- done("It should not succeed");
305
- })
306
- .catch(error => {
307
- expect(error).toBeInstanceOf(TransportExchangeTimeoutError);
308
- expect(mockCancelTransaction).toHaveBeenCalledTimes(2);
309
- done();
310
- });
311
- rxjsScheduler.flush();
312
- }
313
- asyncFn();
314
- });
315
- });
316
- });
317
- it("should disconnect if close is called, even if pending response", done => {
318
- // This is actually a very important test, if we have an ongoing apdu response,
319
- // as in, the device never replied, but we expressed the intention of disconnecting
320
- // we will give it a few seconds and then disconnect regardless. Otherwise we fall
321
- // in the never ending await trap.
322
- async function asyncFn() {
323
- const transport = await BleTransport.open(deviceId);
324
- expect(transport.isConnected).toBe(true);
325
- transport.exchange(Buffer.from("b020000000", "hex"));
326
- BleTransport.disconnectTimeoutMs = 500;
327
- transport.on("disconnect", () => {
328
- done(); // If this is never called, then we're still waiting.
329
- });
330
- await transport.close();
331
- // Expect the timeout for disconnection to be set
332
- expect(transport.disconnectTimeout).not.toBe(undefined);
333
- }
334
- asyncFn();
335
- });
336
- });
337
- });
338
- //# sourceMappingURL=BleTransport.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BleTransport.test.js","sourceRoot":"","sources":["../src/BleTransport.test.ts"],"names":[],"mappings":"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"}