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