@ledgerhq/react-native-hw-transport-ble 6.28.3 → 6.28.4-next.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +30 -0
- package/lib/BleTransport.d.ts +67 -37
- package/lib/BleTransport.d.ts.map +1 -1
- package/lib/BleTransport.js +269 -202
- package/lib/BleTransport.js.map +1 -1
- package/lib/BleTransport.test.d.ts +2 -0
- package/lib/BleTransport.test.d.ts.map +1 -0
- package/lib/BleTransport.test.js +370 -0
- package/lib/BleTransport.test.js.map +1 -0
- package/lib/remapErrors.d.ts +4 -0
- package/lib/remapErrors.d.ts.map +1 -1
- package/lib/remapErrors.js +21 -1
- package/lib/remapErrors.js.map +1 -1
- package/lib/types.d.ts +4 -0
- package/lib/types.d.ts.map +1 -1
- package/lib-es/BleTransport.d.ts +67 -37
- package/lib-es/BleTransport.d.ts.map +1 -1
- package/lib-es/BleTransport.js +269 -202
- package/lib-es/BleTransport.js.map +1 -1
- package/lib-es/BleTransport.test.d.ts +2 -0
- package/lib-es/BleTransport.test.d.ts.map +1 -0
- package/lib-es/BleTransport.test.js +365 -0
- package/lib-es/BleTransport.test.js.map +1 -0
- package/lib-es/remapErrors.d.ts +4 -0
- package/lib-es/remapErrors.d.ts.map +1 -1
- package/lib-es/remapErrors.js +20 -1
- package/lib-es/remapErrors.js.map +1 -1
- package/lib-es/types.d.ts +4 -0
- package/lib-es/types.d.ts.map +1 -1
- package/package.json +16 -5
- package/src/BleTransport.test.ts +275 -0
- package/src/BleTransport.ts +272 -180
- package/src/remapErrors.ts +34 -2
- package/src/types.ts +5 -0
package/lib/BleTransport.js
CHANGED
|
@@ -82,10 +82,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
82
82
|
};
|
|
83
83
|
exports.__esModule = true;
|
|
84
84
|
exports.setReconnectionConfig = void 0;
|
|
85
|
-
/* eslint-disable prefer-template */
|
|
86
85
|
var hw_transport_1 = __importDefault(require("@ledgerhq/hw-transport"));
|
|
87
|
-
var react_native_ble_plx_1 = require("react-native-ble-plx");
|
|
88
|
-
var devices_1 = require("@ledgerhq/devices");
|
|
89
86
|
// ---------------------------------------------------------------------------------------------
|
|
90
87
|
// Since this is a react-native library and metro bundler does not support
|
|
91
88
|
// package exports yet (see: https://github.com/facebook/metro/issues/670)
|
|
@@ -96,6 +93,8 @@ var devices_1 = require("@ledgerhq/devices");
|
|
|
96
93
|
// See: https://github.com/LedgerHQ/ledger-live/pull/879
|
|
97
94
|
var sendAPDU_1 = require("@ledgerhq/devices/lib/ble/sendAPDU");
|
|
98
95
|
var receiveAPDU_1 = require("@ledgerhq/devices/lib/ble/receiveAPDU");
|
|
96
|
+
var react_native_ble_plx_1 = require("react-native-ble-plx");
|
|
97
|
+
var devices_1 = require("@ledgerhq/devices");
|
|
99
98
|
var logs_1 = require("@ledgerhq/logs");
|
|
100
99
|
var rxjs_1 = require("rxjs");
|
|
101
100
|
var operators_1 = require("rxjs/operators");
|
|
@@ -103,25 +102,18 @@ var errors_1 = require("@ledgerhq/errors");
|
|
|
103
102
|
var monitorCharacteristic_1 = require("./monitorCharacteristic");
|
|
104
103
|
var awaitsBleOn_1 = require("./awaitsBleOn");
|
|
105
104
|
var remapErrors_1 = require("./remapErrors");
|
|
106
|
-
var connectOptions = {
|
|
107
|
-
requestMTU: 156,
|
|
108
|
-
connectionPriority: 1
|
|
109
|
-
};
|
|
110
|
-
var transportsCache = {};
|
|
111
|
-
var _bleManager = null;
|
|
112
105
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* Do not use _bleManager directly
|
|
117
|
-
* Only use this instance getter inside BleTransport
|
|
106
|
+
* This is potentially not needed anymore, to be checked if the bug is still
|
|
107
|
+
* happening.
|
|
118
108
|
*/
|
|
119
|
-
var
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
var reconnectionConfig = {
|
|
110
|
+
pairingThreshold: 1000,
|
|
111
|
+
delayAfterFirstPairing: 4000
|
|
112
|
+
};
|
|
113
|
+
var setReconnectionConfig = function (config) {
|
|
114
|
+
reconnectionConfig = config;
|
|
124
115
|
};
|
|
116
|
+
exports.setReconnectionConfig = setReconnectionConfig;
|
|
125
117
|
var retrieveInfos = function (device) {
|
|
126
118
|
if (!device || !device.serviceUUIDs)
|
|
127
119
|
return;
|
|
@@ -133,147 +125,178 @@ var retrieveInfos = function (device) {
|
|
|
133
125
|
return;
|
|
134
126
|
return infos;
|
|
135
127
|
};
|
|
136
|
-
var
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
var delay = function (ms) {
|
|
129
|
+
return new Promise(function (success) { return setTimeout(success, ms); });
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* A cache of Bluetooth transport instances associated with device IDs.
|
|
133
|
+
* Allows efficient storage and retrieval of previously initialized transports.
|
|
134
|
+
* @type {Object.<string, BluetoothTransport>}
|
|
135
|
+
*/
|
|
136
|
+
var transportsCache = {};
|
|
137
|
+
// connectOptions is actually used by react-native-ble-plx even if comment above ConnectionOptions says it's not used
|
|
138
|
+
var connectOptions = {
|
|
139
|
+
// 156 bytes to max the iOS < 10 limit (158 bytes)
|
|
140
|
+
// (185 bytes for iOS >= 10)(up to 512 bytes for Android, but could be blocked at 23 bytes)
|
|
141
|
+
requestMTU: 156,
|
|
142
|
+
// Priority 1 = high. TODO: Check firmware update over BLE PR before merging
|
|
143
|
+
connectionPriority: 1
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Returns the instance of the Bluetooth Low Energy Manager. It initializes it only
|
|
147
|
+
* when it's first needed, preventing the permission prompt happening prematurely.
|
|
148
|
+
* Important: Do NOT access the _bleManager variable directly.
|
|
149
|
+
* Use this function instead.
|
|
150
|
+
* @returns {BleManager} - The instance of the BleManager.
|
|
151
|
+
*/
|
|
152
|
+
var _bleManager = null;
|
|
153
|
+
var bleManagerInstance = function () {
|
|
154
|
+
if (!_bleManager) {
|
|
155
|
+
_bleManager = new react_native_ble_plx_1.BleManager();
|
|
156
|
+
}
|
|
157
|
+
return _bleManager;
|
|
158
|
+
};
|
|
159
|
+
var clearDisconnectTimeout = function (deviceId) {
|
|
160
|
+
var cachedTransport = transportsCache[deviceId];
|
|
161
|
+
if (cachedTransport && cachedTransport.disconnectTimeout) {
|
|
162
|
+
(0, logs_1.log)(TAG, "Clearing queued disconnect");
|
|
163
|
+
clearTimeout(cachedTransport.disconnectTimeout);
|
|
164
|
+
}
|
|
139
165
|
};
|
|
140
|
-
function setReconnectionConfig(config) {
|
|
141
|
-
reconnectionConfig = config;
|
|
142
|
-
}
|
|
143
|
-
exports.setReconnectionConfig = setReconnectionConfig;
|
|
144
|
-
var delay = function (ms) { return new Promise(function (success) { return setTimeout(success, ms); }); };
|
|
145
166
|
function open(deviceOrId, needsReconnect) {
|
|
146
167
|
return __awaiter(this, void 0, void 0, function () {
|
|
147
|
-
var device, devices, connectedDevices, connectedDevicesFiltered, e_1, e_2, res, characteristics, _a, _b, uuid, e_3, e_4_1, deviceModel, serviceUuid, writeUuid, writeCmdUuid, notifyUuid, writeC, writeCmdC, notifyC, characteristics_1, characteristics_1_1, c, notifyObservable, notif, transport,
|
|
168
|
+
var device, devices, connectedDevices, connectedDevicesFiltered, e_1, e_2, res, characteristics, _a, _b, uuid, e_3, e_4_1, deviceModel, serviceUuid, writeUuid, writeCmdUuid, notifyUuid, writeC, writeCmdC, notifyC, characteristics_1, characteristics_1_1, c, notifyObservable, notif, transport, disconnectedSub, onDisconnect, beforeMTUTime, afterMTUTime;
|
|
148
169
|
var _c, _d, e_4, _e, e_5, _f;
|
|
149
170
|
return __generator(this, function (_g) {
|
|
150
171
|
switch (_g.label) {
|
|
151
172
|
case 0:
|
|
152
|
-
|
|
173
|
+
(0, logs_1.log)(TAG, "open with ".concat(deviceOrId));
|
|
174
|
+
if (!(typeof deviceOrId === "string")) return [3 /*break*/, 12];
|
|
153
175
|
if (transportsCache[deviceOrId]) {
|
|
154
|
-
(0, logs_1.log)(
|
|
176
|
+
(0, logs_1.log)(TAG, "Transport in cache, using that.");
|
|
177
|
+
clearDisconnectTimeout(deviceOrId);
|
|
155
178
|
return [2 /*return*/, transportsCache[deviceOrId]];
|
|
156
179
|
}
|
|
157
|
-
(0, logs_1.log)(
|
|
180
|
+
(0, logs_1.log)(TAG, "Tries to open device: ".concat(deviceOrId));
|
|
158
181
|
return [4 /*yield*/, (0, awaitsBleOn_1.awaitsBleOn)(bleManagerInstance())];
|
|
159
182
|
case 1:
|
|
160
183
|
_g.sent();
|
|
161
|
-
if (!!device) return [3 /*break*/, 3];
|
|
162
184
|
return [4 /*yield*/, bleManagerInstance().devices([deviceOrId])];
|
|
163
185
|
case 2:
|
|
164
186
|
devices = _g.sent();
|
|
165
|
-
(0, logs_1.log)(
|
|
187
|
+
(0, logs_1.log)(TAG, "found ".concat(devices.length, " devices"));
|
|
166
188
|
_c = __read(devices, 1), device = _c[0];
|
|
167
|
-
|
|
168
|
-
case 3:
|
|
169
|
-
if (!!device) return [3 /*break*/, 5];
|
|
189
|
+
if (!!device) return [3 /*break*/, 4];
|
|
170
190
|
return [4 /*yield*/, bleManagerInstance().connectedDevices((0, devices_1.getBluetoothServiceUuids)())];
|
|
171
|
-
case
|
|
191
|
+
case 3:
|
|
172
192
|
connectedDevices = _g.sent();
|
|
173
193
|
connectedDevicesFiltered = connectedDevices.filter(function (d) { return d.id === deviceOrId; });
|
|
174
|
-
(0, logs_1.log)(
|
|
194
|
+
(0, logs_1.log)(TAG, "found ".concat(connectedDevicesFiltered.length, " connected devices"));
|
|
175
195
|
_d = __read(connectedDevicesFiltered, 1), device = _d[0];
|
|
196
|
+
_g.label = 4;
|
|
197
|
+
case 4:
|
|
198
|
+
if (!!device) return [3 /*break*/, 11];
|
|
199
|
+
// We still don't have a device, so we attempt to connect to it.
|
|
200
|
+
(0, logs_1.log)(TAG, "connectToDevice(".concat(deviceOrId, ")"));
|
|
176
201
|
_g.label = 5;
|
|
177
202
|
case 5:
|
|
178
|
-
|
|
179
|
-
(0, logs_1.log)("ble-verbose", "connectToDevice(".concat(deviceOrId, ")"));
|
|
180
|
-
_g.label = 6;
|
|
181
|
-
case 6:
|
|
182
|
-
_g.trys.push([6, 8, , 12]);
|
|
203
|
+
_g.trys.push([5, 7, , 11]);
|
|
183
204
|
return [4 /*yield*/, bleManagerInstance().connectToDevice(deviceOrId, connectOptions)];
|
|
184
|
-
case
|
|
205
|
+
case 6:
|
|
185
206
|
device = _g.sent();
|
|
186
|
-
return [3 /*break*/,
|
|
187
|
-
case
|
|
207
|
+
return [3 /*break*/, 11];
|
|
208
|
+
case 7:
|
|
188
209
|
e_1 = _g.sent();
|
|
189
|
-
|
|
190
|
-
|
|
210
|
+
(0, logs_1.log)(TAG, "error code ".concat(e_1.errorCode));
|
|
211
|
+
if (!(e_1.errorCode === react_native_ble_plx_1.BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/, 9];
|
|
212
|
+
// If the MTU update did not work, we try to connect without requesting for a specific MTU
|
|
191
213
|
connectOptions = {};
|
|
192
214
|
return [4 /*yield*/, bleManagerInstance().connectToDevice(deviceOrId)];
|
|
193
|
-
case
|
|
215
|
+
case 8:
|
|
194
216
|
device = _g.sent();
|
|
195
|
-
return [3 /*break*/,
|
|
196
|
-
case
|
|
197
|
-
case
|
|
198
|
-
case
|
|
217
|
+
return [3 /*break*/, 10];
|
|
218
|
+
case 9: throw e_1;
|
|
219
|
+
case 10: return [3 /*break*/, 11];
|
|
220
|
+
case 11:
|
|
199
221
|
if (!device) {
|
|
200
222
|
throw new errors_1.CantOpenDevice();
|
|
201
223
|
}
|
|
202
|
-
return [3 /*break*/,
|
|
203
|
-
case
|
|
224
|
+
return [3 /*break*/, 13];
|
|
225
|
+
case 12:
|
|
226
|
+
// It was already a Device
|
|
204
227
|
device = deviceOrId;
|
|
205
|
-
_g.label =
|
|
206
|
-
case
|
|
228
|
+
_g.label = 13;
|
|
229
|
+
case 13: return [4 /*yield*/, device.isConnected()];
|
|
230
|
+
case 14:
|
|
231
|
+
if (!!(_g.sent())) return [3 /*break*/, 21];
|
|
232
|
+
(0, logs_1.log)(TAG, "not connected. connecting...");
|
|
233
|
+
_g.label = 15;
|
|
207
234
|
case 15:
|
|
208
|
-
|
|
209
|
-
(0, logs_1.log)("ble-verbose", "not connected. connecting...");
|
|
210
|
-
_g.label = 16;
|
|
211
|
-
case 16:
|
|
212
|
-
_g.trys.push([16, 18, , 22]);
|
|
235
|
+
_g.trys.push([15, 17, , 21]);
|
|
213
236
|
return [4 /*yield*/, device.connect(connectOptions)];
|
|
214
|
-
case
|
|
237
|
+
case 16:
|
|
215
238
|
_g.sent();
|
|
216
|
-
return [3 /*break*/,
|
|
217
|
-
case
|
|
239
|
+
return [3 /*break*/, 21];
|
|
240
|
+
case 17:
|
|
218
241
|
e_2 = _g.sent();
|
|
219
|
-
if (!(e_2.errorCode === react_native_ble_plx_1.BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/,
|
|
220
|
-
//
|
|
242
|
+
if (!(e_2.errorCode === react_native_ble_plx_1.BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/, 19];
|
|
243
|
+
// If the MTU update did not work, we try to connect without requesting for a specific MTU
|
|
221
244
|
connectOptions = {};
|
|
222
245
|
return [4 /*yield*/, device.connect()];
|
|
223
|
-
case
|
|
246
|
+
case 18:
|
|
224
247
|
_g.sent();
|
|
225
|
-
return [3 /*break*/,
|
|
226
|
-
case
|
|
227
|
-
case
|
|
228
|
-
case
|
|
229
|
-
case
|
|
248
|
+
return [3 /*break*/, 20];
|
|
249
|
+
case 19: throw e_2;
|
|
250
|
+
case 20: return [3 /*break*/, 21];
|
|
251
|
+
case 21: return [4 /*yield*/, device.discoverAllServicesAndCharacteristics()];
|
|
252
|
+
case 22:
|
|
230
253
|
_g.sent();
|
|
231
254
|
res = retrieveInfos(device);
|
|
232
|
-
if (!!res) return [3 /*break*/,
|
|
255
|
+
if (!!res) return [3 /*break*/, 32];
|
|
256
|
+
_g.label = 23;
|
|
257
|
+
case 23:
|
|
258
|
+
_g.trys.push([23, 30, 31, 32]);
|
|
259
|
+
_a = __values((0, devices_1.getBluetoothServiceUuids)()), _b = _a.next();
|
|
233
260
|
_g.label = 24;
|
|
234
261
|
case 24:
|
|
235
|
-
|
|
236
|
-
|
|
262
|
+
if (!!_b.done) return [3 /*break*/, 29];
|
|
263
|
+
uuid = _b.value;
|
|
237
264
|
_g.label = 25;
|
|
238
265
|
case 25:
|
|
239
|
-
|
|
240
|
-
uuid = _b.value;
|
|
241
|
-
_g.label = 26;
|
|
242
|
-
case 26:
|
|
243
|
-
_g.trys.push([26, 28, , 29]);
|
|
266
|
+
_g.trys.push([25, 27, , 28]);
|
|
244
267
|
return [4 /*yield*/, device.characteristicsForService(uuid)];
|
|
245
|
-
case
|
|
268
|
+
case 26:
|
|
246
269
|
characteristics = _g.sent();
|
|
247
270
|
res = (0, devices_1.getInfosForServiceUuid)(uuid);
|
|
248
|
-
return [3 /*break*/, 30];
|
|
249
|
-
case 28:
|
|
250
|
-
e_3 = _g.sent();
|
|
251
271
|
return [3 /*break*/, 29];
|
|
252
|
-
case
|
|
272
|
+
case 27:
|
|
273
|
+
e_3 = _g.sent();
|
|
274
|
+
return [3 /*break*/, 28];
|
|
275
|
+
case 28:
|
|
253
276
|
_b = _a.next();
|
|
254
|
-
return [3 /*break*/,
|
|
255
|
-
case
|
|
256
|
-
case
|
|
277
|
+
return [3 /*break*/, 24];
|
|
278
|
+
case 29: return [3 /*break*/, 32];
|
|
279
|
+
case 30:
|
|
257
280
|
e_4_1 = _g.sent();
|
|
258
281
|
e_4 = { error: e_4_1 };
|
|
259
|
-
return [3 /*break*/,
|
|
260
|
-
case
|
|
282
|
+
return [3 /*break*/, 32];
|
|
283
|
+
case 31:
|
|
261
284
|
try {
|
|
262
285
|
if (_b && !_b.done && (_e = _a["return"])) _e.call(_a);
|
|
263
286
|
}
|
|
264
287
|
finally { if (e_4) throw e_4.error; }
|
|
265
288
|
return [7 /*endfinally*/];
|
|
266
|
-
case
|
|
289
|
+
case 32:
|
|
267
290
|
if (!res) {
|
|
268
291
|
throw new errors_1.TransportError("service not found", "BLEServiceNotFound");
|
|
269
292
|
}
|
|
270
293
|
deviceModel = res.deviceModel, serviceUuid = res.serviceUuid, writeUuid = res.writeUuid, writeCmdUuid = res.writeCmdUuid, notifyUuid = res.notifyUuid;
|
|
271
|
-
if (!!characteristics) return [3 /*break*/,
|
|
294
|
+
if (!!characteristics) return [3 /*break*/, 34];
|
|
272
295
|
return [4 /*yield*/, device.characteristicsForService(serviceUuid)];
|
|
273
|
-
case
|
|
296
|
+
case 33:
|
|
274
297
|
characteristics = _g.sent();
|
|
275
|
-
_g.label =
|
|
276
|
-
case
|
|
298
|
+
_g.label = 34;
|
|
299
|
+
case 34:
|
|
277
300
|
if (!characteristics) {
|
|
278
301
|
throw new errors_1.TransportError("service not found", "BLEServiceNotFound");
|
|
279
302
|
}
|
|
@@ -299,23 +322,23 @@ function open(deviceOrId, needsReconnect) {
|
|
|
299
322
|
finally { if (e_5) throw e_5.error; }
|
|
300
323
|
}
|
|
301
324
|
if (!writeC) {
|
|
302
|
-
throw new errors_1.TransportError("write characteristic not found", "
|
|
325
|
+
throw new errors_1.TransportError("write characteristic not found", "BLECharacteristicNotFound");
|
|
303
326
|
}
|
|
304
327
|
if (!notifyC) {
|
|
305
|
-
throw new errors_1.TransportError("notify characteristic not found", "
|
|
328
|
+
throw new errors_1.TransportError("notify characteristic not found", "BLECharacteristicNotFound");
|
|
306
329
|
}
|
|
307
330
|
if (!writeC.isWritableWithResponse) {
|
|
308
|
-
throw new errors_1.TransportError("write characteristic not writableWithResponse", "
|
|
331
|
+
throw new errors_1.TransportError("write characteristic not writableWithResponse", "BLECharacteristicInvalid");
|
|
309
332
|
}
|
|
310
333
|
if (!notifyC.isNotifiable) {
|
|
311
|
-
throw new errors_1.TransportError("notify characteristic not notifiable", "
|
|
334
|
+
throw new errors_1.TransportError("notify characteristic not notifiable", "BLECharacteristicInvalid");
|
|
312
335
|
}
|
|
313
336
|
if (writeCmdC) {
|
|
314
337
|
if (!writeCmdC.isWritableWithoutResponse) {
|
|
315
|
-
throw new errors_1.TransportError("write cmd characteristic not writableWithoutResponse", "
|
|
338
|
+
throw new errors_1.TransportError("write cmd characteristic not writableWithoutResponse", "BLECharacteristicInvalid");
|
|
316
339
|
}
|
|
317
340
|
}
|
|
318
|
-
(0, logs_1.log)(
|
|
341
|
+
(0, logs_1.log)(TAG, "device.mtu=".concat(device.mtu));
|
|
319
342
|
notifyObservable = (0, monitorCharacteristic_1.monitorCharacteristic)(notifyC).pipe((0, operators_1.catchError)(function (e) {
|
|
320
343
|
// LL-9033 fw 2.0.2 introduced this case, we silence the inner unhandled error.
|
|
321
344
|
var msg = String(e);
|
|
@@ -328,58 +351,57 @@ function open(deviceOrId, needsReconnect) {
|
|
|
328
351
|
(0, logs_1.log)("ble-frame", "<= " + value.toString("hex"));
|
|
329
352
|
}), (0, operators_1.share)());
|
|
330
353
|
notif = notifyObservable.subscribe();
|
|
331
|
-
transport = new
|
|
332
|
-
return [4 /*yield*/, transport.requestConnectionPriority("High")];
|
|
333
|
-
case 36:
|
|
334
|
-
_g.sent();
|
|
354
|
+
transport = new BleTransport(device, writeC, writeCmdC, notifyObservable, deviceModel);
|
|
335
355
|
onDisconnect = function (e) {
|
|
356
|
+
transport.isConnected = false;
|
|
336
357
|
transport.notYetDisconnected = false;
|
|
337
358
|
notif.unsubscribe();
|
|
338
|
-
disconnectedSub.remove();
|
|
359
|
+
disconnectedSub === null || disconnectedSub === void 0 ? void 0 : disconnectedSub.remove();
|
|
360
|
+
clearDisconnectTimeout(transport.id);
|
|
339
361
|
delete transportsCache[transport.id];
|
|
340
|
-
(0, logs_1.log)(
|
|
362
|
+
(0, logs_1.log)(TAG, "BleTransport(".concat(transport.id, ") disconnected"));
|
|
341
363
|
transport.emit("disconnect", e);
|
|
342
364
|
};
|
|
343
365
|
// eslint-disable-next-line require-atomic-updates
|
|
344
366
|
transportsCache[transport.id] = transport;
|
|
367
|
+
beforeMTUTime = Date.now();
|
|
345
368
|
disconnectedSub = device.onDisconnected(function (e) {
|
|
346
369
|
if (!transport.notYetDisconnected)
|
|
347
370
|
return;
|
|
348
371
|
onDisconnect(e);
|
|
349
372
|
});
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
_g.trys.push([37, , 39, 45]);
|
|
373
|
+
_g.label = 35;
|
|
374
|
+
case 35:
|
|
375
|
+
_g.trys.push([35, , 37, 43]);
|
|
354
376
|
return [4 /*yield*/, transport.inferMTU()];
|
|
355
|
-
case
|
|
377
|
+
case 36:
|
|
356
378
|
_g.sent();
|
|
357
|
-
return [3 /*break*/,
|
|
358
|
-
case
|
|
379
|
+
return [3 /*break*/, 43];
|
|
380
|
+
case 37:
|
|
359
381
|
afterMTUTime = Date.now();
|
|
360
|
-
if (!reconnectionConfig) return [3 /*break*/,
|
|
382
|
+
if (!reconnectionConfig) return [3 /*break*/, 41];
|
|
361
383
|
// workaround for #279: we need to open() again if we come the first time here,
|
|
362
384
|
// to make sure we do a disconnect() after the first pairing time
|
|
363
385
|
// because of a firmware bug
|
|
364
386
|
if (afterMTUTime - beforeMTUTime < reconnectionConfig.pairingThreshold) {
|
|
365
387
|
needsReconnect = false; // (optim) there is likely no new pairing done because mtu answer was fast.
|
|
366
388
|
}
|
|
367
|
-
if (!needsReconnect) return [3 /*break*/,
|
|
389
|
+
if (!needsReconnect) return [3 /*break*/, 40];
|
|
368
390
|
// necessary time for the bonding workaround
|
|
369
|
-
return [4 /*yield*/,
|
|
370
|
-
case
|
|
391
|
+
return [4 /*yield*/, BleTransport.disconnect(transport.id)["catch"](function () { })];
|
|
392
|
+
case 38:
|
|
371
393
|
// necessary time for the bonding workaround
|
|
372
394
|
_g.sent();
|
|
373
395
|
return [4 /*yield*/, delay(reconnectionConfig.delayAfterFirstPairing)];
|
|
374
|
-
case
|
|
396
|
+
case 39:
|
|
375
397
|
_g.sent();
|
|
398
|
+
_g.label = 40;
|
|
399
|
+
case 40: return [3 /*break*/, 42];
|
|
400
|
+
case 41:
|
|
401
|
+
needsReconnect = false;
|
|
376
402
|
_g.label = 42;
|
|
377
|
-
case 42: return [
|
|
403
|
+
case 42: return [7 /*endfinally*/];
|
|
378
404
|
case 43:
|
|
379
|
-
needsReconnect = false;
|
|
380
|
-
_g.label = 44;
|
|
381
|
-
case 44: return [7 /*endfinally*/];
|
|
382
|
-
case 45:
|
|
383
405
|
if (needsReconnect) {
|
|
384
406
|
return [2 /*return*/, open(device, false)];
|
|
385
407
|
}
|
|
@@ -391,16 +413,22 @@ function open(deviceOrId, needsReconnect) {
|
|
|
391
413
|
/**
|
|
392
414
|
* react-native bluetooth BLE implementation
|
|
393
415
|
* @example
|
|
394
|
-
* import
|
|
416
|
+
* import BleTransport from "@ledgerhq/react-native-hw-transport-ble";
|
|
395
417
|
*/
|
|
396
|
-
var
|
|
397
|
-
|
|
398
|
-
|
|
418
|
+
var TAG = "ble-verbose";
|
|
419
|
+
var BleTransport = /** @class */ (function (_super) {
|
|
420
|
+
__extends(BleTransport, _super);
|
|
421
|
+
function BleTransport(device, writeCharacteristic, writeCmdCharacteristic, notifyObservable, deviceModel) {
|
|
399
422
|
var _this = _super.call(this) || this;
|
|
423
|
+
_this.disconnectTimeout = null;
|
|
424
|
+
_this.isConnected = true;
|
|
400
425
|
_this.mtuSize = 20;
|
|
401
426
|
_this.notYetDisconnected = true;
|
|
402
427
|
/**
|
|
403
|
-
*
|
|
428
|
+
* Send data to the device using a low level API.
|
|
429
|
+
* It's recommended to use the "send" method for a higher level API.
|
|
430
|
+
* @param {Buffer} apdu - The data to send.
|
|
431
|
+
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
404
432
|
*/
|
|
405
433
|
_this.exchange = function (apdu) {
|
|
406
434
|
return _this.exchangeAtomicImpl(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
@@ -411,9 +439,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
411
439
|
_b.trys.push([0, 2, , 5]);
|
|
412
440
|
msgIn = apdu.toString("hex");
|
|
413
441
|
(0, logs_1.log)("apdu", "=> ".concat(msgIn));
|
|
414
|
-
return [4 /*yield*/, (0, rxjs_1.merge)(
|
|
415
|
-
// $FlowFixMe
|
|
416
|
-
this.notifyObservable.pipe(receiveAPDU_1.receiveAPDU), (0, sendAPDU_1.sendAPDU)(this.write, apdu, this.mtuSize)).toPromise()];
|
|
442
|
+
return [4 /*yield*/, (0, rxjs_1.merge)(this.notifyObservable.pipe(receiveAPDU_1.receiveAPDU), (0, sendAPDU_1.sendAPDU)(this.write, apdu, this.mtuSize)).toPromise()];
|
|
417
443
|
case 1:
|
|
418
444
|
data = _b.sent();
|
|
419
445
|
msgOut = data.toString("hex");
|
|
@@ -436,6 +462,12 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
436
462
|
});
|
|
437
463
|
}); });
|
|
438
464
|
};
|
|
465
|
+
/**
|
|
466
|
+
* Do not call this directly unless you know what you're doing. Communication
|
|
467
|
+
* with a Ledger device should be through the {@link exchange} method.
|
|
468
|
+
* @param buffer
|
|
469
|
+
* @param txid
|
|
470
|
+
*/
|
|
439
471
|
_this.write = function (buffer, txid) { return __awaiter(_this, void 0, void 0, function () {
|
|
440
472
|
var e_7, e_8;
|
|
441
473
|
return __generator(this, function (_b) {
|
|
@@ -473,15 +505,17 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
473
505
|
_this.writeCmdCharacteristic = writeCmdCharacteristic;
|
|
474
506
|
_this.notifyObservable = notifyObservable;
|
|
475
507
|
_this.deviceModel = deviceModel;
|
|
476
|
-
(0, logs_1.log)(
|
|
508
|
+
(0, logs_1.log)(TAG, "BleTransport(".concat(String(_this.id), ") new instance"));
|
|
509
|
+
clearDisconnectTimeout(_this.id);
|
|
477
510
|
return _this;
|
|
478
511
|
}
|
|
479
512
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
513
|
+
* Listen to state changes on the bleManagerInstance and notify the
|
|
514
|
+
* specified observer.
|
|
515
|
+
* @param observer
|
|
516
|
+
* @returns TransportSubscription
|
|
483
517
|
*/
|
|
484
|
-
|
|
518
|
+
BleTransport.observeState = function (observer) {
|
|
485
519
|
var emitFromState = function (type) {
|
|
486
520
|
observer.next({
|
|
487
521
|
type: type,
|
|
@@ -495,48 +529,52 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
495
529
|
};
|
|
496
530
|
/**
|
|
497
531
|
* Scan for bluetooth Ledger devices
|
|
532
|
+
* @param observer Device is partial in order to avoid the live-common/this dep
|
|
533
|
+
* @returns TransportSubscription
|
|
498
534
|
*/
|
|
499
|
-
|
|
535
|
+
BleTransport.listen = function (observer) {
|
|
500
536
|
var _this = this;
|
|
501
|
-
(0, logs_1.log)(
|
|
537
|
+
(0, logs_1.log)(TAG, "listening for devices");
|
|
502
538
|
var unsubscribed;
|
|
503
539
|
var stateSub = bleManagerInstance().onStateChange(function (state) { return __awaiter(_this, void 0, void 0, function () {
|
|
504
540
|
var devices;
|
|
505
541
|
return __generator(this, function (_b) {
|
|
506
542
|
switch (_b.label) {
|
|
507
543
|
case 0:
|
|
508
|
-
if (!(state === "PoweredOn")) return [3 /*break*/,
|
|
544
|
+
if (!(state === "PoweredOn")) return [3 /*break*/, 4];
|
|
509
545
|
stateSub.remove();
|
|
510
546
|
return [4 /*yield*/, bleManagerInstance().connectedDevices((0, devices_1.getBluetoothServiceUuids)())];
|
|
511
547
|
case 1:
|
|
512
548
|
devices = _b.sent();
|
|
513
549
|
if (unsubscribed)
|
|
514
550
|
return [2 /*return*/];
|
|
515
|
-
return [
|
|
516
|
-
|
|
517
|
-
|
|
551
|
+
if (!devices.length) return [3 /*break*/, 3];
|
|
552
|
+
(0, logs_1.log)(TAG, "disconnecting from devices");
|
|
553
|
+
return [4 /*yield*/, Promise.all(devices.map(function (d) { return BleTransport.disconnect(d.id)["catch"](function () { }); }))];
|
|
518
554
|
case 2:
|
|
519
555
|
_b.sent();
|
|
556
|
+
_b.label = 3;
|
|
557
|
+
case 3:
|
|
520
558
|
if (unsubscribed)
|
|
521
559
|
return [2 /*return*/];
|
|
522
|
-
bleManagerInstance().startDeviceScan((0, devices_1.getBluetoothServiceUuids)(), null, function (bleError,
|
|
560
|
+
bleManagerInstance().startDeviceScan((0, devices_1.getBluetoothServiceUuids)(), null, function (bleError, scannedDevice) {
|
|
523
561
|
if (bleError) {
|
|
524
|
-
observer.error(mapBleErrorToHwTransportError(bleError));
|
|
562
|
+
observer.error((0, remapErrors_1.mapBleErrorToHwTransportError)(bleError));
|
|
525
563
|
unsubscribe();
|
|
526
564
|
return;
|
|
527
565
|
}
|
|
528
|
-
var res = retrieveInfos(
|
|
566
|
+
var res = retrieveInfos(scannedDevice);
|
|
529
567
|
var deviceModel = res && res.deviceModel;
|
|
530
|
-
if (
|
|
568
|
+
if (scannedDevice) {
|
|
531
569
|
observer.next({
|
|
532
570
|
type: "add",
|
|
533
|
-
descriptor:
|
|
571
|
+
descriptor: scannedDevice,
|
|
534
572
|
deviceModel: deviceModel
|
|
535
573
|
});
|
|
536
574
|
}
|
|
537
575
|
});
|
|
538
|
-
_b.label =
|
|
539
|
-
case
|
|
576
|
+
_b.label = 4;
|
|
577
|
+
case 4: return [2 /*return*/];
|
|
540
578
|
}
|
|
541
579
|
});
|
|
542
580
|
}); }, true);
|
|
@@ -544,7 +582,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
544
582
|
unsubscribed = true;
|
|
545
583
|
bleManagerInstance().stopDeviceScan();
|
|
546
584
|
stateSub.remove();
|
|
547
|
-
(0, logs_1.log)(
|
|
585
|
+
(0, logs_1.log)(TAG, "done listening.");
|
|
548
586
|
};
|
|
549
587
|
return {
|
|
550
588
|
unsubscribe: unsubscribe
|
|
@@ -552,19 +590,22 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
552
590
|
};
|
|
553
591
|
/**
|
|
554
592
|
* Open a BLE transport
|
|
555
|
-
* @param {
|
|
593
|
+
* @param {Device | string} deviceOrId
|
|
556
594
|
*/
|
|
557
|
-
|
|
595
|
+
BleTransport.open = function (deviceOrId) {
|
|
558
596
|
return __awaiter(this, void 0, void 0, function () {
|
|
559
597
|
return __generator(this, function (_b) {
|
|
560
598
|
return [2 /*return*/, open(deviceOrId, true)];
|
|
561
599
|
});
|
|
562
600
|
});
|
|
563
601
|
};
|
|
564
|
-
|
|
565
|
-
|
|
602
|
+
/**
|
|
603
|
+
* Negotiate with the device the maximum transfer unit for the ble frames
|
|
604
|
+
* @returns Promise<number>
|
|
605
|
+
*/
|
|
606
|
+
BleTransport.prototype.inferMTU = function () {
|
|
566
607
|
return __awaiter(this, void 0, void 0, function () {
|
|
567
|
-
var mtu
|
|
608
|
+
var mtu;
|
|
568
609
|
var _this = this;
|
|
569
610
|
return __generator(this, function (_b) {
|
|
570
611
|
switch (_b.label) {
|
|
@@ -582,12 +623,11 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
582
623
|
throw maybeError;
|
|
583
624
|
}), (0, operators_1.first)(function (buffer) { return buffer.readUInt8(0) === 0x08; }), (0, operators_1.map)(function (buffer) { return buffer.readUInt8(5); })), (0, rxjs_1.defer)(function () { return (0, rxjs_1.from)(_this.write(Buffer.from([0x08, 0, 0, 0, 0]))); }).pipe((0, operators_1.ignoreElements)())).toPromise()];
|
|
584
625
|
case 1:
|
|
585
|
-
mtu =
|
|
586
|
-
(_b.sent()) + 3;
|
|
626
|
+
mtu = _b.sent();
|
|
587
627
|
return [3 /*break*/, 4];
|
|
588
628
|
case 2:
|
|
589
629
|
e_9 = _b.sent();
|
|
590
|
-
(0, logs_1.log)("ble-error", "inferMTU got " +
|
|
630
|
+
(0, logs_1.log)("ble-error", "inferMTU got " + JSON.stringify(e_9));
|
|
591
631
|
return [4 /*yield*/, bleManagerInstance()
|
|
592
632
|
.cancelDeviceConnection(this.id)["catch"](function () { })];
|
|
593
633
|
case 3:
|
|
@@ -599,94 +639,121 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
599
639
|
}); })];
|
|
600
640
|
case 1:
|
|
601
641
|
_b.sent();
|
|
602
|
-
if (mtu >
|
|
603
|
-
mtuSize = mtu
|
|
604
|
-
(0, logs_1.log)(
|
|
605
|
-
this.mtuSize = mtuSize;
|
|
642
|
+
if (mtu > 20) {
|
|
643
|
+
this.mtuSize = mtu;
|
|
644
|
+
(0, logs_1.log)(TAG, "BleTransport(".concat(this.id, ") mtu set to ").concat(this.mtuSize));
|
|
606
645
|
}
|
|
607
646
|
return [2 /*return*/, this.mtuSize];
|
|
608
647
|
}
|
|
609
648
|
});
|
|
610
649
|
});
|
|
611
650
|
};
|
|
612
|
-
|
|
651
|
+
/**
|
|
652
|
+
* Exposed method from the ble-plx library
|
|
653
|
+
* Request the connection priority for the given device.
|
|
654
|
+
* @param {"Balanced" | "High" | "LowPower"} connectionPriority: Connection priority.
|
|
655
|
+
* @returns {Promise<Device>} Connected device.
|
|
656
|
+
*/
|
|
657
|
+
BleTransport.prototype.requestConnectionPriority = function (connectionPriority) {
|
|
613
658
|
return __awaiter(this, void 0, void 0, function () {
|
|
614
659
|
return __generator(this, function (_b) {
|
|
615
660
|
switch (_b.label) {
|
|
616
661
|
case 0: return [4 /*yield*/, (0, remapErrors_1.decoratePromiseErrors)(this.device.requestConnectionPriority(react_native_ble_plx_1.ConnectionPriority[connectionPriority]))];
|
|
617
|
-
case 1:
|
|
618
|
-
_b.sent();
|
|
619
|
-
return [2 /*return*/];
|
|
662
|
+
case 1: return [2 /*return*/, _b.sent()];
|
|
620
663
|
}
|
|
621
664
|
});
|
|
622
665
|
});
|
|
623
666
|
};
|
|
624
|
-
|
|
625
|
-
|
|
667
|
+
/**
|
|
668
|
+
* We intentionally do not immediately close a transport connection.
|
|
669
|
+
* Instead, we queue the disconnect and wait for a future connection to dismiss the event.
|
|
670
|
+
* This approach prevents unnecessary disconnects and reconnects. We use the isConnected
|
|
671
|
+
* flag to ensure that we do not trigger a disconnect if the current cached transport has
|
|
672
|
+
* already been disconnected.
|
|
673
|
+
* @returns {Promise<void>}
|
|
674
|
+
*/
|
|
675
|
+
BleTransport.prototype.close = function () {
|
|
626
676
|
return __awaiter(this, void 0, void 0, function () {
|
|
677
|
+
var resolve, disconnectPromise;
|
|
678
|
+
var _this = this;
|
|
627
679
|
return __generator(this, function (_b) {
|
|
628
680
|
switch (_b.label) {
|
|
629
681
|
case 0:
|
|
630
|
-
|
|
631
|
-
|
|
682
|
+
disconnectPromise = new Promise(function (innerResolve) {
|
|
683
|
+
resolve = innerResolve;
|
|
684
|
+
});
|
|
685
|
+
clearDisconnectTimeout(this.id);
|
|
686
|
+
(0, logs_1.log)(TAG, "Queuing a disconnect");
|
|
687
|
+
this.disconnectTimeout = setTimeout(function () {
|
|
688
|
+
(0, logs_1.log)(TAG, "Triggering a disconnect from ".concat(_this.id));
|
|
689
|
+
if (_this.isConnected) {
|
|
690
|
+
BleTransport.disconnect(_this.id)["catch"](function () { })["finally"](resolve);
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
resolve();
|
|
694
|
+
}
|
|
695
|
+
}, BleTransport.disconnectTimeoutMs);
|
|
696
|
+
// The closure will occur no later than 5s, triggered either by disconnection
|
|
697
|
+
// or the actual response of the apdu.
|
|
698
|
+
return [4 /*yield*/, Promise.race([
|
|
699
|
+
this.exchangeBusyPromise || Promise.resolve(),
|
|
700
|
+
disconnectPromise,
|
|
701
|
+
])];
|
|
632
702
|
case 1:
|
|
703
|
+
// The closure will occur no later than 5s, triggered either by disconnection
|
|
704
|
+
// or the actual response of the apdu.
|
|
633
705
|
_b.sent();
|
|
634
|
-
|
|
635
|
-
case 2: return [2 /*return*/];
|
|
706
|
+
return [2 /*return*/];
|
|
636
707
|
}
|
|
637
708
|
});
|
|
638
709
|
});
|
|
639
710
|
};
|
|
640
711
|
var _a;
|
|
641
|
-
_a =
|
|
712
|
+
_a = BleTransport;
|
|
713
|
+
BleTransport.disconnectTimeoutMs = 5000;
|
|
642
714
|
/**
|
|
643
715
|
*
|
|
644
716
|
*/
|
|
645
|
-
|
|
717
|
+
BleTransport.isSupported = function () {
|
|
646
718
|
return Promise.resolve(typeof react_native_ble_plx_1.BleManager === "function");
|
|
647
719
|
};
|
|
648
720
|
/**
|
|
649
721
|
*
|
|
650
722
|
*/
|
|
651
|
-
|
|
652
|
-
bleManagerInstance().setLogLevel(level);
|
|
653
|
-
};
|
|
654
|
-
BluetoothTransport.list = function () {
|
|
723
|
+
BleTransport.list = function () {
|
|
655
724
|
throw new Error("not implemented");
|
|
656
725
|
};
|
|
657
726
|
/**
|
|
658
|
-
*
|
|
727
|
+
* Exposed method from the ble-plx library
|
|
728
|
+
* Sets new log level for native module's logging mechanism.
|
|
729
|
+
* @param string logLevel New log level to be set.
|
|
730
|
+
*/
|
|
731
|
+
BleTransport.setLogLevel = function (logLevel) {
|
|
732
|
+
if (Object.values(react_native_ble_plx_1.LogLevel).includes(logLevel)) {
|
|
733
|
+
bleManagerInstance().setLogLevel(logLevel);
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
throw new Error("".concat(logLevel, " is not a valid LogLevel"));
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
/**
|
|
740
|
+
* Exposed method from the ble-plx library
|
|
741
|
+
* Disconnects from {@link Device} if it's connected or cancels pending connection.
|
|
659
742
|
*/
|
|
660
|
-
|
|
743
|
+
BleTransport.disconnect = function (id) { return __awaiter(void 0, void 0, void 0, function () {
|
|
661
744
|
return __generator(_a, function (_b) {
|
|
662
745
|
switch (_b.label) {
|
|
663
746
|
case 0:
|
|
664
|
-
(0, logs_1.log)(
|
|
747
|
+
(0, logs_1.log)(TAG, "user disconnect(".concat(id, ")"));
|
|
665
748
|
return [4 /*yield*/, bleManagerInstance().cancelDeviceConnection(id)];
|
|
666
749
|
case 1:
|
|
667
750
|
_b.sent();
|
|
751
|
+
(0, logs_1.log)(TAG, "disconnected");
|
|
668
752
|
return [2 /*return*/];
|
|
669
753
|
}
|
|
670
754
|
});
|
|
671
755
|
}); };
|
|
672
|
-
return
|
|
756
|
+
return BleTransport;
|
|
673
757
|
}(hw_transport_1["default"]));
|
|
674
|
-
exports["default"] =
|
|
675
|
-
var bleErrorToHwTransportError = new Map([
|
|
676
|
-
[react_native_ble_plx_1.BleErrorCode.ScanStartFailed, errors_1.HwTransportErrorType.BleScanStartFailed],
|
|
677
|
-
[
|
|
678
|
-
react_native_ble_plx_1.BleErrorCode.LocationServicesDisabled,
|
|
679
|
-
errors_1.HwTransportErrorType.BleLocationServicesDisabled,
|
|
680
|
-
],
|
|
681
|
-
[
|
|
682
|
-
react_native_ble_plx_1.BleErrorCode.BluetoothUnauthorized,
|
|
683
|
-
errors_1.HwTransportErrorType.BleBluetoothUnauthorized,
|
|
684
|
-
],
|
|
685
|
-
]);
|
|
686
|
-
var mapBleErrorToHwTransportError = function (bleError) {
|
|
687
|
-
var message = "".concat(bleError.message, ". Origin: ").concat(bleError.errorCode);
|
|
688
|
-
var inferedType = bleErrorToHwTransportError.get(bleError.errorCode);
|
|
689
|
-
var type = !inferedType ? errors_1.HwTransportErrorType.Unknown : inferedType;
|
|
690
|
-
return new errors_1.HwTransportError(type, message);
|
|
691
|
-
};
|
|
758
|
+
exports["default"] = BleTransport;
|
|
692
759
|
//# sourceMappingURL=BleTransport.js.map
|