@onekeyfe/hd-transport-react-native 1.2.3-alpha.8 → 1.2.3

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/dist/index.js CHANGED
@@ -46,6 +46,76 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
46
46
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
47
47
  };
48
48
 
49
+ const lastKeyMissingAt = new Map();
50
+ const listeners$1 = new Set();
51
+ let unsubscribeNative$1;
52
+ const normalizeDeviceId$1 = (deviceId) => deviceId.toLowerCase();
53
+ const getCapableBleUtils$1 = () => {
54
+ if (reactNative.Platform.OS !== 'android')
55
+ return undefined;
56
+ const bleUtils = BleUtils__default["default"];
57
+ if (typeof bleUtils.supportsDeviceKeyMissing !== 'function' ||
58
+ typeof bleUtils.onDeviceKeyMissing !== 'function') {
59
+ return undefined;
60
+ }
61
+ return bleUtils.supportsDeviceKeyMissing() ? bleUtils : undefined;
62
+ };
63
+ const isBleKeyMissingSupported = () => getCapableBleUtils$1() !== undefined;
64
+ const startBleKeyMissingTracking = () => {
65
+ if (unsubscribeNative$1)
66
+ return true;
67
+ const bleUtils = getCapableBleUtils$1();
68
+ if (!(bleUtils === null || bleUtils === void 0 ? void 0 : bleUtils.onDeviceKeyMissing))
69
+ return false;
70
+ unsubscribeNative$1 = bleUtils.onDeviceKeyMissing(event => {
71
+ if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
72
+ return;
73
+ const deviceId = normalizeDeviceId$1(event.id);
74
+ lastKeyMissingAt.set(deviceId, Date.now());
75
+ listeners$1.forEach(listener => listener(deviceId));
76
+ });
77
+ return true;
78
+ };
79
+ const stopBleKeyMissingTracking = () => {
80
+ unsubscribeNative$1 === null || unsubscribeNative$1 === void 0 ? void 0 : unsubscribeNative$1();
81
+ unsubscribeNative$1 = undefined;
82
+ lastKeyMissingAt.clear();
83
+ listeners$1.clear();
84
+ };
85
+ const hasBleKeyMissingSince = (deviceId, sinceMs) => {
86
+ const at = lastKeyMissingAt.get(normalizeDeviceId$1(deviceId));
87
+ return at !== undefined && at >= sinceMs;
88
+ };
89
+ const onBleKeyMissing = (deviceId, callback) => {
90
+ const target = normalizeDeviceId$1(deviceId);
91
+ const listener = id => {
92
+ if (id === target)
93
+ callback();
94
+ };
95
+ listeners$1.add(listener);
96
+ return () => {
97
+ listeners$1.delete(listener);
98
+ };
99
+ };
100
+ const waitForBleKeyMissing = (deviceId, sinceMs, timeoutMs) => {
101
+ if (!startBleKeyMissingTracking())
102
+ return Promise.resolve(false);
103
+ if (hasBleKeyMissingSince(deviceId, sinceMs))
104
+ return Promise.resolve(true);
105
+ return new Promise(resolve => {
106
+ const settle = (found) => {
107
+ clearTimeout(timer);
108
+ cleanup();
109
+ resolve(found);
110
+ };
111
+ const cleanup = onBleKeyMissing(deviceId, () => {
112
+ if (hasBleKeyMissingSince(deviceId, sinceMs))
113
+ settle(true);
114
+ });
115
+ const timer = setTimeout(() => settle(false), timeoutMs);
116
+ });
117
+ };
118
+
49
119
  let activeLogger;
50
120
  const setBleLogger = (logger) => {
51
121
  activeLogger = logger;
@@ -70,17 +140,35 @@ const bondFailureReasons = {
70
140
  };
71
141
  const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
72
142
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
73
- const onDeviceBondState = (bleMacAddress, signal) => new Promise((resolve, reject) => {
143
+ const SYSTEM_BONDING_RESTART_WINDOW_MS = 1500;
144
+ const createBondFailureError = (bondState) => {
145
+ var _a;
146
+ const nativeReason = 'reason' in bondState && typeof bondState.reason === 'number' ? bondState.reason : undefined;
147
+ const reason = nativeReason === undefined ? 'unknown' : (_a = bondFailureReasons[nativeReason]) !== null && _a !== void 0 ? _a : 'unknown';
148
+ const params = Object.assign({ phase: 'bond', reason }, (nativeReason === undefined ? {} : { nativeReason }));
149
+ if (reason === 'timeout') {
150
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', params);
151
+ }
152
+ if (reason === 'canceled') {
153
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'Bluetooth pairing canceled', params);
154
+ }
155
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing failed', params);
156
+ };
157
+ const onDeviceBondState = (bleMacAddress, signal, options) => new Promise((resolve, reject) => {
74
158
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
75
159
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
76
160
  return;
77
161
  }
162
+ let pendingFailure;
78
163
  const cleanup = () => {
79
164
  if (timeout) {
80
165
  clearTimeout(timeout);
81
166
  }
167
+ if (pendingFailure)
168
+ clearTimeout(pendingFailure);
82
169
  if (cleanupListener)
83
170
  cleanupListener();
171
+ cleanupKeyMissing === null || cleanupKeyMissing === void 0 ? void 0 : cleanupKeyMissing();
84
172
  signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
85
173
  };
86
174
  const onAbort = () => {
@@ -95,35 +183,44 @@ const onDeviceBondState = (bleMacAddress, signal) => new Promise((resolve, rejec
95
183
  reason: 'timeout',
96
184
  }));
97
185
  }, 60 * 1000);
186
+ const cleanupKeyMissing = startBleKeyMissingTracking()
187
+ ? onBleKeyMissing(bleMacAddress, () => {
188
+ cleanup();
189
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, undefined, {
190
+ phase: 'bond',
191
+ reason: 'key_missing',
192
+ }));
193
+ })
194
+ : undefined;
98
195
  const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
99
- var _a, _b;
196
+ var _a;
100
197
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
101
198
  return;
102
199
  }
103
200
  const { bondState } = peripheral;
104
201
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
105
202
  const hasFailed = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
203
+ const hasRestarted = bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING';
106
204
  Logger.debug('onDeviceBondState bondState:', bondState);
107
205
  if (hasBonded) {
108
206
  cleanup();
109
207
  resolve(peripheral);
110
208
  }
209
+ else if (hasRestarted && pendingFailure) {
210
+ clearTimeout(pendingFailure);
211
+ pendingFailure = undefined;
212
+ }
213
+ else if (hasFailed && (options === null || options === void 0 ? void 0 : options.systemInitiated)) {
214
+ if (pendingFailure)
215
+ clearTimeout(pendingFailure);
216
+ pendingFailure = setTimeout(() => {
217
+ cleanup();
218
+ reject(createBondFailureError(bondState));
219
+ }, SYSTEM_BONDING_RESTART_WINDOW_MS);
220
+ }
111
221
  else if (hasFailed) {
112
222
  cleanup();
113
- const nativeReason = 'reason' in bondState && typeof bondState.reason === 'number'
114
- ? bondState.reason
115
- : undefined;
116
- const reason = nativeReason === undefined ? 'unknown' : (_b = bondFailureReasons[nativeReason]) !== null && _b !== void 0 ? _b : 'unknown';
117
- const params = Object.assign({ phase: 'bond', reason }, (nativeReason === undefined ? {} : { nativeReason }));
118
- if (reason === 'timeout') {
119
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', params));
120
- }
121
- else if (reason === 'canceled') {
122
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'Bluetooth pairing canceled', params));
123
- }
124
- else {
125
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing failed', params));
126
- }
223
+ reject(createBondFailureError(bondState));
127
224
  }
128
225
  });
129
226
  });
@@ -231,6 +328,172 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
231
328
  }, ms);
232
329
  });
233
330
 
331
+ const HCI_PIN_OR_KEY_MISSING = 0x06;
332
+ const lastEncryption = new Map();
333
+ const lastAclDisconnectAt = new Map();
334
+ const listeners = new Set();
335
+ let unsubscribeNative;
336
+ const normalizeDeviceId = (deviceId) => deviceId.toLowerCase();
337
+ const isEncrypted = (record) => record.status === 0 && record.enabled;
338
+ const getCapableBleUtils = () => {
339
+ if (reactNative.Platform.OS !== 'android')
340
+ return undefined;
341
+ const bleUtils = BleUtils__default["default"];
342
+ if (typeof bleUtils.supportsDeviceEncryptionChange !== 'function' ||
343
+ typeof bleUtils.onDeviceEncryptionChange !== 'function' ||
344
+ typeof bleUtils.onDeviceAclDisconnected !== 'function') {
345
+ return undefined;
346
+ }
347
+ return bleUtils.supportsDeviceEncryptionChange() ? bleUtils : undefined;
348
+ };
349
+ const notify = (deviceId) => {
350
+ listeners.forEach(listener => listener(deviceId));
351
+ };
352
+ const startBleEncryptionTracking = () => {
353
+ if (unsubscribeNative)
354
+ return true;
355
+ const bleUtils = getCapableBleUtils();
356
+ if (!(bleUtils === null || bleUtils === void 0 ? void 0 : bleUtils.onDeviceEncryptionChange) || !bleUtils.onDeviceAclDisconnected)
357
+ return false;
358
+ unsubscribeNative = [
359
+ bleUtils.onDeviceEncryptionChange(event => {
360
+ if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
361
+ return;
362
+ const deviceId = normalizeDeviceId(event.id);
363
+ lastEncryption.set(deviceId, {
364
+ at: Date.now(),
365
+ status: Number(event.status),
366
+ enabled: event.enabled === true,
367
+ });
368
+ notify(deviceId);
369
+ }),
370
+ bleUtils.onDeviceAclDisconnected(event => {
371
+ if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
372
+ return;
373
+ const deviceId = normalizeDeviceId(event.id);
374
+ lastAclDisconnectAt.set(deviceId, Date.now());
375
+ notify(deviceId);
376
+ }),
377
+ ];
378
+ return true;
379
+ };
380
+ const stopBleEncryptionTracking = () => {
381
+ unsubscribeNative === null || unsubscribeNative === void 0 ? void 0 : unsubscribeNative.forEach(unsubscribe => unsubscribe());
382
+ unsubscribeNative = undefined;
383
+ lastEncryption.clear();
384
+ lastAclDisconnectAt.clear();
385
+ listeners.clear();
386
+ };
387
+ const markBleLinkEncrypted = (deviceId) => {
388
+ if (!unsubscribeNative)
389
+ return;
390
+ lastEncryption.set(normalizeDeviceId(deviceId), { at: Date.now(), status: 0, enabled: true });
391
+ };
392
+ const waitForAndroidLinkEncryption = ({ deviceId, linkStartedAt, resultTimeoutMs, repairTimeoutMs, keyMissingGraceMs, signal, onRepairStarted, }) => {
393
+ if (!startBleEncryptionTracking())
394
+ return Promise.resolve('unresolved');
395
+ startBleKeyMissingTracking();
396
+ const target = normalizeDeviceId(deviceId);
397
+ const previous = lastEncryption.get(target);
398
+ const previousDropAt = lastAclDisconnectAt.get(target);
399
+ if (previous &&
400
+ previous.at < linkStartedAt &&
401
+ isEncrypted(previous) &&
402
+ (previousDropAt === undefined || previousDropAt < previous.at)) {
403
+ return Promise.resolve('already-encrypted');
404
+ }
405
+ return new Promise((resolve, reject) => {
406
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
407
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
408
+ return;
409
+ }
410
+ let repairStartedAt;
411
+ let droppedDuringRepair = false;
412
+ let timer;
413
+ let settled = false;
414
+ const cleanup = () => {
415
+ settled = true;
416
+ if (timer)
417
+ clearTimeout(timer);
418
+ listeners.delete(onLinkEvent);
419
+ cleanupKeyMissing();
420
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
421
+ };
422
+ const finish = (result) => {
423
+ cleanup();
424
+ resolve(result);
425
+ };
426
+ const fail = (error) => {
427
+ cleanup();
428
+ reject(error);
429
+ };
430
+ const arm = (ms, onExpire) => {
431
+ if (timer)
432
+ clearTimeout(timer);
433
+ timer = setTimeout(onExpire, ms);
434
+ };
435
+ const bondInvalid = () => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, undefined, {
436
+ phase: 'connect',
437
+ reason: 'key_missing',
438
+ });
439
+ const evaluate = () => {
440
+ if (settled)
441
+ return;
442
+ const record = lastEncryption.get(target);
443
+ const dropAt = lastAclDisconnectAt.get(target);
444
+ if (repairStartedAt === undefined) {
445
+ if (hasBleKeyMissingSince(target, linkStartedAt)) {
446
+ fail(bondInvalid());
447
+ return;
448
+ }
449
+ if (dropAt !== undefined && dropAt >= linkStartedAt) {
450
+ finish('unresolved');
451
+ return;
452
+ }
453
+ if (!record || record.at < linkStartedAt)
454
+ return;
455
+ if (isEncrypted(record)) {
456
+ finish('encrypted');
457
+ return;
458
+ }
459
+ if (record.status !== HCI_PIN_OR_KEY_MISSING) {
460
+ finish('unresolved');
461
+ return;
462
+ }
463
+ repairStartedAt = record.at;
464
+ onRepairStarted === null || onRepairStarted === void 0 ? void 0 : onRepairStarted();
465
+ arm(repairTimeoutMs, () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', {
466
+ phase: 'bond',
467
+ reason: 'timeout',
468
+ })));
469
+ return;
470
+ }
471
+ if (hasBleKeyMissingSince(target, repairStartedAt)) {
472
+ fail(bondInvalid());
473
+ return;
474
+ }
475
+ if (record && record.at > repairStartedAt && isEncrypted(record)) {
476
+ finish('re-paired');
477
+ return;
478
+ }
479
+ if (!droppedDuringRepair && dropAt !== undefined && dropAt >= repairStartedAt) {
480
+ droppedDuringRepair = true;
481
+ arm(keyMissingGraceMs, () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected)));
482
+ }
483
+ };
484
+ const onLinkEvent = id => {
485
+ if (id === target)
486
+ evaluate();
487
+ };
488
+ const onAbort = () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
489
+ listeners.add(onLinkEvent);
490
+ const cleanupKeyMissing = onBleKeyMissing(target, evaluate);
491
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
492
+ arm(resultTimeoutMs, () => finish('unresolved'));
493
+ evaluate();
494
+ });
495
+ };
496
+
234
497
  const BLE_PLX_DEVICE_DISCONNECTED = 201;
235
498
  const IOS_PERIPHERAL_DISCONNECTED = 7;
236
499
  const nativeErrorText$1 = (error) => [error.reason, error.message]
@@ -386,6 +649,18 @@ const shouldRethrowProtocolProbeError = (error) => {
386
649
  code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
387
650
  code === hdShared.HardwareErrorCode.BleWriteCharacteristicError);
388
651
  };
652
+ const ANDROID_KEY_MISSING_LINK_WINDOW_MS = 10000;
653
+ const ANDROID_KEY_MISSING_GRACE_MS = 500;
654
+ const ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS = 1500;
655
+ const ANDROID_SYSTEM_REPAIR_TIMEOUT_MS = 35000;
656
+ const isAndroidLinkLossError = (error) => {
657
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
658
+ return (isNativeBleDisconnectError(error) ||
659
+ code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
660
+ code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
661
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
662
+ code === hdShared.HardwareErrorCode.BleConnectedError);
663
+ };
389
664
  const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
390
665
  const DEVICE_SCAN_TIMEOUT_MS = 3000;
391
666
  const IOS_NOTIFY_READY_DELAY_MS = 150;
@@ -583,6 +858,7 @@ class ReactNativeBleTransport {
583
858
  this.silentDetections = new Map();
584
859
  this.androidGattCacheRefreshes = new Set();
585
860
  this.staleBondErrors = new Map();
861
+ this.androidLinkStartedAt = new Map();
586
862
  this.acquiringProtocolV2 = new Set();
587
863
  this.protocolV2Assemblers = new Map();
588
864
  this.protocolV2FrameQueues = new Map();
@@ -630,6 +906,10 @@ class ReactNativeBleTransport {
630
906
  init(logger, emitter) {
631
907
  setBleLogger(logger);
632
908
  this.emitter = emitter;
909
+ if (reactNative.Platform.OS === 'android') {
910
+ startBleKeyMissingTracking();
911
+ startBleEncryptionTracking();
912
+ }
633
913
  }
634
914
  configure(signedData) {
635
915
  const messages = parseConfigure(signedData);
@@ -1016,7 +1296,14 @@ class ReactNativeBleTransport {
1016
1296
  if (!uuid) {
1017
1297
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
1018
1298
  }
1019
- return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
1299
+ return this.runLifecycleOperation(uuid, () => __awaiter(this, void 0, void 0, function* () {
1300
+ try {
1301
+ return yield this.acquireUnlocked(input);
1302
+ }
1303
+ catch (error) {
1304
+ throw yield this.resolveAndroidBondInvalid(uuid, error);
1305
+ }
1306
+ }));
1020
1307
  });
1021
1308
  }
1022
1309
  acquireUnlocked(input) {
@@ -1071,6 +1358,7 @@ class ReactNativeBleTransport {
1071
1358
  }
1072
1359
  let device = null;
1073
1360
  const isAndroid = reactNative.Platform.OS === 'android';
1361
+ let androidBondedBeforeConnect = false;
1074
1362
  const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
1075
1363
  let nativeConnectOptions = connectOptions;
1076
1364
  if (isAndroid) {
@@ -1098,10 +1386,16 @@ class ReactNativeBleTransport {
1098
1386
  if (this.stopped)
1099
1387
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1100
1388
  if (reactNative.Platform.OS === 'android') {
1389
+ startBleKeyMissingTracking();
1390
+ startBleEncryptionTracking();
1391
+ this.androidLinkStartedAt.delete(uuid);
1101
1392
  try {
1102
1393
  const bondState = yield pairDevice(uuid);
1394
+ androidBondedBeforeConnect = !bondState.bonding && bondState.bonded;
1103
1395
  if (bondState.bonding) {
1104
- yield onDeviceBondState(uuid, this.bondAbortController.signal);
1396
+ yield onDeviceBondState(uuid, this.bondAbortController.signal, {
1397
+ systemInitiated: bondState.initiated === false,
1398
+ });
1105
1399
  }
1106
1400
  else if (!bondState.bonded) {
1107
1401
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
@@ -1113,6 +1407,7 @@ class ReactNativeBleTransport {
1113
1407
  }));
1114
1408
  throw error;
1115
1409
  }
1410
+ this.androidLinkStartedAt.set(uuid, Date.now());
1116
1411
  }
1117
1412
  if (this.stopped)
1118
1413
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
@@ -1270,7 +1565,13 @@ class ReactNativeBleTransport {
1270
1565
  if (shouldMapProtocolV2StaleBond) {
1271
1566
  this.acquiringProtocolV2.add(uuid);
1272
1567
  }
1568
+ let linkEncryption;
1273
1569
  try {
1570
+ if (androidBondedBeforeConnect && !skipProtocolProbe) {
1571
+ linkEncryption = yield this.waitForAndroidLinkSecurity(uuid);
1572
+ if (this.stopped)
1573
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1574
+ }
1274
1575
  yield this.installTransportForAcquire(uuid, acquiredDevice, {
1275
1576
  writeCharacteristic,
1276
1577
  notifyCharacteristic,
@@ -1309,6 +1610,9 @@ class ReactNativeBleTransport {
1309
1610
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
1310
1611
  }
1311
1612
  this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
1613
+ if (linkEncryption === 'unresolved') {
1614
+ markBleLinkEncrypted(uuid);
1615
+ }
1312
1616
  return { uuid, protocolType };
1313
1617
  }
1314
1618
  catch (error) {
@@ -1510,14 +1814,64 @@ class ReactNativeBleTransport {
1510
1814
  if (!protocol) {
1511
1815
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
1512
1816
  }
1513
- if (protocol === 'V2') {
1514
- return this.callProtocolV2(uuid, name, data, options);
1515
- }
1516
1817
  const forceRun = name === 'Initialize' || name === 'Cancel';
1517
- if (this.runPromise && !forceRun) {
1818
+ if (protocol !== 'V2' && this.runPromise && !forceRun) {
1518
1819
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1519
1820
  }
1520
- return this.callProtocolV1(uuid, name, data, options);
1821
+ try {
1822
+ return protocol === 'V2'
1823
+ ? yield this.callProtocolV2(uuid, name, data, options)
1824
+ : yield this.callProtocolV1(uuid, name, data, options);
1825
+ }
1826
+ catch (error) {
1827
+ throw yield this.resolveAndroidBondInvalid(uuid, error);
1828
+ }
1829
+ });
1830
+ }
1831
+ resolveAndroidBondInvalid(uuid, error) {
1832
+ return __awaiter(this, void 0, void 0, function* () {
1833
+ if (reactNative.Platform.OS !== 'android' || !isBleKeyMissingSupported())
1834
+ return error;
1835
+ if (hdShared.isBleStaleBondHardwareError(error) || !isAndroidLinkLossError(error))
1836
+ return error;
1837
+ const linkStartedAt = this.androidLinkStartedAt.get(uuid);
1838
+ if (linkStartedAt === undefined ||
1839
+ Date.now() - linkStartedAt > ANDROID_KEY_MISSING_LINK_WINDOW_MS) {
1840
+ return error;
1841
+ }
1842
+ if (!(yield waitForBleKeyMissing(uuid, linkStartedAt, ANDROID_KEY_MISSING_GRACE_MS))) {
1843
+ return error;
1844
+ }
1845
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android key missing, bond is invalid:', uuid);
1846
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, undefined, {
1847
+ phase: 'connect',
1848
+ reason: 'key_missing',
1849
+ });
1850
+ });
1851
+ }
1852
+ waitForAndroidLinkSecurity(uuid) {
1853
+ return __awaiter(this, void 0, void 0, function* () {
1854
+ const linkStartedAt = this.androidLinkStartedAt.get(uuid);
1855
+ if (linkStartedAt === undefined)
1856
+ return 'unresolved';
1857
+ const waitStartedAt = Date.now();
1858
+ const result = yield waitForAndroidLinkEncryption({
1859
+ deviceId: uuid,
1860
+ linkStartedAt,
1861
+ resultTimeoutMs: ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS,
1862
+ repairTimeoutMs: ANDROID_SYSTEM_REPAIR_TIMEOUT_MS,
1863
+ keyMissingGraceMs: ANDROID_KEY_MISSING_GRACE_MS,
1864
+ signal: this.bondAbortController.signal,
1865
+ onRepairStarted: () => {
1866
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android bond lost, waiting for system re-pairing:', uuid);
1867
+ },
1868
+ });
1869
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android link encryption', {
1870
+ connectIdSuffix: uuid.slice(-8),
1871
+ result,
1872
+ waitedMs: Date.now() - waitStartedAt,
1873
+ });
1874
+ return result;
1521
1875
  });
1522
1876
  }
1523
1877
  callProtocolV1(uuid, name, data, options) {
@@ -1733,6 +2087,9 @@ class ReactNativeBleTransport {
1733
2087
  this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
1734
2088
  this.androidPriorityResetTimers.clear();
1735
2089
  this.androidHighPriorityDevices.clear();
2090
+ this.androidLinkStartedAt.clear();
2091
+ stopBleKeyMissingTracking();
2092
+ stopBleEncryptionTracking();
1736
2093
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1737
2094
  (_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
1738
2095
  this.runPromise = null;
@@ -2766,8 +3123,12 @@ class ReactNativeBleTransport {
2766
3123
  }
2767
3124
  }
2768
3125
 
3126
+ exports.ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS = ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS;
3127
+ exports.ANDROID_KEY_MISSING_GRACE_MS = ANDROID_KEY_MISSING_GRACE_MS;
3128
+ exports.ANDROID_KEY_MISSING_LINK_WINDOW_MS = ANDROID_KEY_MISSING_LINK_WINDOW_MS;
2769
3129
  exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
2770
3130
  exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
3131
+ exports.ANDROID_SYSTEM_REPAIR_TIMEOUT_MS = ANDROID_SYSTEM_REPAIR_TIMEOUT_MS;
2771
3132
  exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
2772
3133
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
2773
3134
  exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.3-alpha.8",
3
+ "version": "1.2.3",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,11 +20,11 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-core": "1.2.3-alpha.8",
24
- "@onekeyfe/hd-shared": "1.2.3-alpha.8",
25
- "@onekeyfe/hd-transport": "1.2.3-alpha.8",
26
- "@onekeyfe/react-native-ble-utils": "0.1.6",
23
+ "@onekeyfe/hd-core": "1.2.3",
24
+ "@onekeyfe/hd-shared": "1.2.3",
25
+ "@onekeyfe/hd-transport": "1.2.3",
26
+ "@onekeyfe/react-native-ble-utils": "0.1.9",
27
27
  "react-native-ble-plx": "3.5.1"
28
28
  },
29
- "gitHead": "170aac4b7ca98bf24b5dd36b9729c98a10389161"
29
+ "gitHead": "de8e0beb9d993464fbcac6231d7efe501d789c7d"
30
30
  }