@onekeyfe/hd-transport-web-device 1.2.8-alpha.15 → 1.2.8-alpha.17
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/__tests__/webusb-identity-probe.test.ts +570 -3
- package/dist/index.d.ts +11 -0
- package/dist/index.js +215 -18
- package/dist/webusb.d.ts +11 -0
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/webusb.ts +212 -18
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
|
51
51
|
const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
52
52
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
53
53
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
54
|
+
const USB_DEVICE_IN_USE = 'USB device is already in use';
|
|
54
55
|
const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
|
|
55
56
|
const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
|
|
56
57
|
const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
|
|
@@ -58,6 +59,7 @@ let activeWebUsbTransport;
|
|
|
58
59
|
let usbDisconnectListenerAttached = false;
|
|
59
60
|
const identityProbeHandles = new WeakSet();
|
|
60
61
|
const openingHandles = new WeakSet();
|
|
62
|
+
const normalHandleOwners = new WeakMap();
|
|
61
63
|
function registerActiveWebUsbTransport(instance, usb) {
|
|
62
64
|
activeWebUsbTransport = instance;
|
|
63
65
|
if (usbDisconnectListenerAttached)
|
|
@@ -87,6 +89,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
87
89
|
this.staleProtocolPaths = new Set();
|
|
88
90
|
this.acquiredPaths = new Set();
|
|
89
91
|
this.identityProbeDevices = new Map();
|
|
92
|
+
this.normalDevices = new Map();
|
|
93
|
+
this.pendingHandleOperations = new Set();
|
|
94
|
+
this.identityProbeCleanupPaths = new Set();
|
|
90
95
|
this.probedDeviceObjects = new Map();
|
|
91
96
|
this.deviceEndpoints = new Map();
|
|
92
97
|
this.name = 'WebUsbTransport';
|
|
@@ -108,6 +113,102 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
108
113
|
if (!this.identityProbe)
|
|
109
114
|
registerActiveWebUsbTransport(this, usb);
|
|
110
115
|
}
|
|
116
|
+
stop() {
|
|
117
|
+
this.stopped = true;
|
|
118
|
+
this.acquiredPaths.clear();
|
|
119
|
+
if (activeWebUsbTransport === this)
|
|
120
|
+
activeWebUsbTransport = undefined;
|
|
121
|
+
if (!this.stopPromise) {
|
|
122
|
+
this.stopPromise = this.stopResources().catch(error => {
|
|
123
|
+
this.stopPromise = undefined;
|
|
124
|
+
throw error;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return this.stopPromise;
|
|
128
|
+
}
|
|
129
|
+
stopResources() {
|
|
130
|
+
var _a, _b, _c;
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
let cleanupError;
|
|
133
|
+
try {
|
|
134
|
+
yield this.disposeProtocolV2UsbLinks('WebUSB transport stopped');
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
cleanupError = error;
|
|
138
|
+
}
|
|
139
|
+
yield Promise.allSettled([...this.pendingHandleOperations]);
|
|
140
|
+
const handles = this.identityProbe
|
|
141
|
+
? [...this.identityProbeDevices].map(([path, device]) => [device, path])
|
|
142
|
+
: [...this.normalDevices];
|
|
143
|
+
for (const [device, path] of handles) {
|
|
144
|
+
if (!this.identityProbe && normalHandleOwners.get(device) !== this) {
|
|
145
|
+
this.normalDevices.delete(device);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
try {
|
|
149
|
+
if (device.opened) {
|
|
150
|
+
const iface = (_b = (_a = this.deviceEndpoints.get(path)) === null || _a === void 0 ? void 0 : _a.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
151
|
+
try {
|
|
152
|
+
yield device.releaseInterface(iface);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] stop releaseInterface failed:', error);
|
|
156
|
+
}
|
|
157
|
+
yield device.close();
|
|
158
|
+
if (device.opened)
|
|
159
|
+
throw new Error('WebUSB handle remains open after stop');
|
|
160
|
+
}
|
|
161
|
+
if (this.identityProbe) {
|
|
162
|
+
identityProbeHandles.delete(device);
|
|
163
|
+
this.identityProbeDevices.delete(path);
|
|
164
|
+
this.identityProbeCleanupPaths.delete(path);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
normalHandleOwners.delete(device);
|
|
168
|
+
this.normalDevices.delete(device);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
cleanupError !== null && cleanupError !== void 0 ? cleanupError : (cleanupError = error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.deviceList = [];
|
|
177
|
+
this.deviceProtocol.clear();
|
|
178
|
+
this.confirmedDeviceProtocols.clear();
|
|
179
|
+
this.deviceProtocolHints.clear();
|
|
180
|
+
this.staleProtocolPaths.clear();
|
|
181
|
+
this.probedDeviceObjects.clear();
|
|
182
|
+
if (!this.normalDevices.size && !this.identityProbeDevices.size) {
|
|
183
|
+
this.deviceEndpoints.clear();
|
|
184
|
+
}
|
|
185
|
+
if (cleanupError) {
|
|
186
|
+
throw cleanupError instanceof Error
|
|
187
|
+
? cleanupError
|
|
188
|
+
: new Error(this.getErrorMessage(cleanupError));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
assertRunning() {
|
|
193
|
+
if (this.stopped) {
|
|
194
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'WebUSB transport is stopped');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
runHandleOperation(operation) {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
this.assertRunning();
|
|
200
|
+
const pending = Promise.resolve(operation());
|
|
201
|
+
this.pendingHandleOperations.add(pending);
|
|
202
|
+
try {
|
|
203
|
+
const result = yield pending;
|
|
204
|
+
this.assertRunning();
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
this.pendingHandleOperations.delete(pending);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
111
212
|
emitDeviceDisconnect(path, device) {
|
|
112
213
|
var _a, _b;
|
|
113
214
|
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
@@ -155,15 +256,36 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
155
256
|
}
|
|
156
257
|
enumerate() {
|
|
157
258
|
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
for (const path of this.identityProbeCleanupPaths) {
|
|
260
|
+
try {
|
|
261
|
+
yield this.release(path);
|
|
262
|
+
}
|
|
263
|
+
catch (_a) {
|
|
264
|
+
}
|
|
265
|
+
}
|
|
158
266
|
yield this.getConnectedDevices();
|
|
159
267
|
return this.deviceList;
|
|
160
268
|
});
|
|
161
269
|
}
|
|
162
270
|
getConnectedDevices() {
|
|
271
|
+
var _a;
|
|
163
272
|
return __awaiter(this, void 0, void 0, function* () {
|
|
273
|
+
this.assertRunning();
|
|
164
274
|
if (!this.usb)
|
|
165
275
|
return [];
|
|
166
276
|
const devices = yield this.usb.getDevices();
|
|
277
|
+
this.assertRunning();
|
|
278
|
+
for (const owner of new Set(devices.map(device => normalHandleOwners.get(device)))) {
|
|
279
|
+
if (owner === null || owner === void 0 ? void 0 : owner.stopped) {
|
|
280
|
+
try {
|
|
281
|
+
yield owner.stop();
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] stopped owner cleanup failed:', error);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
this.assertRunning();
|
|
167
289
|
const onekeyDevices = devices.filter(dev => {
|
|
168
290
|
const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
|
|
169
291
|
return isOneKey && !hdShared.isKnownTrezorWebUsbDevice(dev);
|
|
@@ -190,12 +312,16 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
190
312
|
acquire(input) {
|
|
191
313
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
192
314
|
return __awaiter(this, void 0, void 0, function* () {
|
|
315
|
+
this.assertRunning();
|
|
193
316
|
if (!input.path)
|
|
194
317
|
return;
|
|
195
318
|
if (this.identityProbe) {
|
|
196
319
|
yield this.getConnectedDevices();
|
|
197
320
|
this.claimIdentityProbeHandle(input.path, yield this.findDevice(input.path));
|
|
198
321
|
}
|
|
322
|
+
else {
|
|
323
|
+
this.claimNormalHandle(input.path, yield this.findDevice(input.path));
|
|
324
|
+
}
|
|
199
325
|
try {
|
|
200
326
|
yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
|
|
201
327
|
yield this.closeOpenDevice(input.path);
|
|
@@ -245,12 +371,14 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
245
371
|
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
246
372
|
}
|
|
247
373
|
const detectedProtocol = yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
|
|
374
|
+
this.assertRunning();
|
|
248
375
|
this.confirmedDeviceProtocols.set(input.path, detectedProtocol);
|
|
249
376
|
const probedDevice = (_g = this.deviceList.find(d => d.path === input.path)) === null || _g === void 0 ? void 0 : _g.device;
|
|
250
377
|
if (probedDevice) {
|
|
251
378
|
this.probedDeviceObjects.set(input.path, probedDevice);
|
|
252
379
|
}
|
|
253
380
|
}
|
|
381
|
+
this.assertRunning();
|
|
254
382
|
this.acquiredPaths.add(input.path);
|
|
255
383
|
return yield Promise.resolve(input.path);
|
|
256
384
|
}
|
|
@@ -262,6 +390,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
262
390
|
}
|
|
263
391
|
finally {
|
|
264
392
|
this.releaseIdentityProbeHandle(input.path);
|
|
393
|
+
this.releaseNormalHandles(input.path);
|
|
265
394
|
}
|
|
266
395
|
throw e;
|
|
267
396
|
}
|
|
@@ -342,10 +471,12 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
342
471
|
return __awaiter(this, void 0, void 0, function* () {
|
|
343
472
|
const maxRetries = 5;
|
|
344
473
|
for (let i = 0; i < maxRetries; i++) {
|
|
474
|
+
this.assertRunning();
|
|
345
475
|
try {
|
|
346
476
|
return yield this.connectToDevice(path, first);
|
|
347
477
|
}
|
|
348
478
|
catch (e) {
|
|
479
|
+
this.assertRunning();
|
|
349
480
|
if (e instanceof hdShared.HardwareError && e.errorCode === hdShared.HardwareErrorCode.BridgeNeedsPermission) {
|
|
350
481
|
throw e;
|
|
351
482
|
}
|
|
@@ -388,17 +519,20 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
388
519
|
connectToDevice(path, first) {
|
|
389
520
|
var _a;
|
|
390
521
|
return __awaiter(this, void 0, void 0, function* () {
|
|
522
|
+
this.assertRunning();
|
|
391
523
|
let device = yield this.findDevice(path);
|
|
392
524
|
if (this.identityProbe && this.identityProbeDevices.get(path) !== device) {
|
|
393
525
|
yield this.closeOpenDevice(path);
|
|
394
526
|
this.releaseIdentityProbeHandle(path);
|
|
395
527
|
this.claimIdentityProbeHandle(path, device);
|
|
396
528
|
}
|
|
529
|
+
if (!this.identityProbe)
|
|
530
|
+
this.claimNormalHandle(path, device);
|
|
397
531
|
this.assertHandleAvailable(device);
|
|
398
532
|
if (!device.opened) {
|
|
399
533
|
openingHandles.add(device);
|
|
400
534
|
try {
|
|
401
|
-
yield device.open();
|
|
535
|
+
yield this.runHandleOperation(() => device.open());
|
|
402
536
|
}
|
|
403
537
|
catch (error) {
|
|
404
538
|
return yield this.throwWebUsbIoError(path, 'open', error);
|
|
@@ -409,9 +543,10 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
409
543
|
}
|
|
410
544
|
if (first || this.deviceProtocol.get(path) !== 'V1') {
|
|
411
545
|
try {
|
|
412
|
-
yield device.reset();
|
|
546
|
+
yield this.runHandleOperation(() => device.reset());
|
|
413
547
|
}
|
|
414
548
|
catch (error) {
|
|
549
|
+
this.assertRunning();
|
|
415
550
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] reset before claim failed, continuing:', error);
|
|
416
551
|
}
|
|
417
552
|
}
|
|
@@ -422,11 +557,13 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
422
557
|
this.releaseIdentityProbeHandle(path);
|
|
423
558
|
this.claimIdentityProbeHandle(path, device);
|
|
424
559
|
}
|
|
560
|
+
if (!this.identityProbe)
|
|
561
|
+
this.claimNormalHandle(path, device);
|
|
425
562
|
this.assertHandleAvailable(device);
|
|
426
563
|
if (!device.opened) {
|
|
427
564
|
openingHandles.add(device);
|
|
428
565
|
try {
|
|
429
|
-
yield device.open();
|
|
566
|
+
yield this.runHandleOperation(() => device.open());
|
|
430
567
|
}
|
|
431
568
|
catch (error) {
|
|
432
569
|
return yield this.throwWebUsbIoError(path, 'open', error);
|
|
@@ -438,12 +575,12 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
438
575
|
if (first ||
|
|
439
576
|
!device.configuration ||
|
|
440
577
|
device.configuration.configurationValue !== this.configurationId) {
|
|
441
|
-
yield device.selectConfiguration(this.configurationId);
|
|
578
|
+
yield this.runHandleOperation(() => device.selectConfiguration(this.configurationId));
|
|
442
579
|
}
|
|
443
580
|
const endpoints = this.discoverEndpoints(device);
|
|
444
581
|
this.deviceEndpoints.set(path, endpoints);
|
|
445
582
|
try {
|
|
446
|
-
yield device.claimInterface(endpoints.interfaceNumber);
|
|
583
|
+
yield this.runHandleOperation(() => device.claimInterface(endpoints.interfaceNumber));
|
|
447
584
|
}
|
|
448
585
|
catch (error) {
|
|
449
586
|
return this.throwWebUsbIoError(path, 'claimInterface', error);
|
|
@@ -453,29 +590,63 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
453
590
|
});
|
|
454
591
|
}
|
|
455
592
|
assertHandleAvailable(device) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
593
|
+
this.assertRunning();
|
|
594
|
+
const normalOwner = normalHandleOwners.get(device);
|
|
595
|
+
if ((normalOwner && normalOwner !== this) ||
|
|
596
|
+
(identityProbeHandles.has(device) &&
|
|
597
|
+
![...this.identityProbeDevices.values()].includes(device))) {
|
|
598
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, USB_DEVICE_IN_USE);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
claimNormalHandle(path, device) {
|
|
602
|
+
this.assertHandleAvailable(device);
|
|
603
|
+
normalHandleOwners.set(device, this);
|
|
604
|
+
this.normalDevices.set(device, path);
|
|
605
|
+
}
|
|
606
|
+
releaseNormalHandles(path) {
|
|
607
|
+
if (this.stopped)
|
|
608
|
+
return;
|
|
609
|
+
for (const [device, ownedPath] of this.normalDevices) {
|
|
610
|
+
if (ownedPath === path) {
|
|
611
|
+
normalHandleOwners.delete(device);
|
|
612
|
+
this.normalDevices.delete(device);
|
|
613
|
+
}
|
|
459
614
|
}
|
|
460
615
|
}
|
|
616
|
+
isHandleOwnershipError(error) {
|
|
617
|
+
return (error instanceof hdShared.HardwareError &&
|
|
618
|
+
error.errorCode === hdShared.HardwareErrorCode.RuntimeError &&
|
|
619
|
+
this.getErrorMessage(error).includes(USB_DEVICE_IN_USE));
|
|
620
|
+
}
|
|
461
621
|
claimIdentityProbeHandle(path, device) {
|
|
462
|
-
|
|
463
|
-
|
|
622
|
+
this.assertRunning();
|
|
623
|
+
if (device.opened ||
|
|
624
|
+
openingHandles.has(device) ||
|
|
625
|
+
identityProbeHandles.has(device) ||
|
|
626
|
+
normalHandleOwners.has(device)) {
|
|
627
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, USB_DEVICE_IN_USE);
|
|
464
628
|
}
|
|
465
629
|
identityProbeHandles.add(device);
|
|
466
630
|
this.identityProbeDevices.set(path, device);
|
|
467
631
|
}
|
|
468
632
|
releaseIdentityProbeHandle(path) {
|
|
633
|
+
if (this.stopped)
|
|
634
|
+
return;
|
|
469
635
|
const device = this.identityProbeDevices.get(path);
|
|
470
|
-
if (device === null || device === void 0 ? void 0 : device.opened)
|
|
636
|
+
if (device === null || device === void 0 ? void 0 : device.opened) {
|
|
637
|
+
this.identityProbeCleanupPaths.add(path);
|
|
471
638
|
return;
|
|
639
|
+
}
|
|
472
640
|
if (device)
|
|
473
641
|
identityProbeHandles.delete(device);
|
|
474
642
|
this.identityProbeDevices.delete(path);
|
|
643
|
+
this.identityProbeCleanupPaths.delete(path);
|
|
475
644
|
}
|
|
476
645
|
closeOpenDevice(path) {
|
|
477
646
|
var _a, _b, _c, _d;
|
|
478
647
|
return __awaiter(this, void 0, void 0, function* () {
|
|
648
|
+
if (this.stopped)
|
|
649
|
+
return;
|
|
479
650
|
const current = this.identityProbe
|
|
480
651
|
? this.identityProbeDevices.get(path)
|
|
481
652
|
: (_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.device;
|
|
@@ -485,13 +656,14 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
485
656
|
const endpoints = this.deviceEndpoints.get(path);
|
|
486
657
|
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
487
658
|
try {
|
|
488
|
-
yield current.releaseInterface(ifaceNum);
|
|
659
|
+
yield this.runHandleOperation(() => current.releaseInterface(ifaceNum));
|
|
489
660
|
}
|
|
490
661
|
catch (error) {
|
|
491
662
|
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
492
663
|
}
|
|
664
|
+
this.assertHandleAvailable(current);
|
|
493
665
|
try {
|
|
494
|
-
yield current.close();
|
|
666
|
+
yield this.runHandleOperation(() => current.close());
|
|
495
667
|
}
|
|
496
668
|
catch (error) {
|
|
497
669
|
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] close before reconnect failed:', error);
|
|
@@ -503,15 +675,18 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
503
675
|
clearEndpointHalt(device, direction, endpointNumber) {
|
|
504
676
|
var _a;
|
|
505
677
|
return __awaiter(this, void 0, void 0, function* () {
|
|
678
|
+
this.assertHandleAvailable(device);
|
|
506
679
|
try {
|
|
507
|
-
yield device.clearHalt(direction, endpointNumber);
|
|
680
|
+
yield this.runHandleOperation(() => device.clearHalt(direction, endpointNumber));
|
|
508
681
|
}
|
|
509
682
|
catch (error) {
|
|
683
|
+
this.assertRunning();
|
|
510
684
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] clearHalt ${direction} endpoint ${endpointNumber} failed, continuing:`, error);
|
|
511
685
|
}
|
|
512
686
|
});
|
|
513
687
|
}
|
|
514
688
|
assertAcquired(path) {
|
|
689
|
+
this.assertRunning();
|
|
515
690
|
if (!this.acquiredPaths.has(path)) {
|
|
516
691
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device is not acquired for ${path}`);
|
|
517
692
|
}
|
|
@@ -568,7 +743,8 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
568
743
|
throwWebUsbIoError(path, operation, error) {
|
|
569
744
|
var _a;
|
|
570
745
|
return __awaiter(this, void 0, void 0, function* () {
|
|
571
|
-
|
|
746
|
+
this.assertRunning();
|
|
747
|
+
if (this.isHandleOwnershipError(error) || this.isWebUsbIoHardwareError(error))
|
|
572
748
|
throw error;
|
|
573
749
|
if (error instanceof transport.ProtocolV2LinkError && error.code !== 'io')
|
|
574
750
|
throw error;
|
|
@@ -602,7 +778,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
602
778
|
return /LIBUSB_ERROR_ACCESS|\b(?:access|permission) denied\b/i.test(message);
|
|
603
779
|
}
|
|
604
780
|
isRetryablePacketIoError(error) {
|
|
605
|
-
if (this.
|
|
781
|
+
if (this.stopped)
|
|
782
|
+
return false;
|
|
783
|
+
if (this.isHandleOwnershipError(error) || this.isWebUsbIoHardwareError(error))
|
|
606
784
|
return false;
|
|
607
785
|
const message = this.getErrorMessage(error).toLowerCase();
|
|
608
786
|
if (this.isWebUsbPermissionDeniedMessage(message))
|
|
@@ -621,21 +799,27 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
621
799
|
this.Log.debug(`[WebUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
|
|
622
800
|
this.staleProtocolPaths.add(path);
|
|
623
801
|
yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
802
|
+
this.assertRunning();
|
|
624
803
|
try {
|
|
625
804
|
const currentDevice = yield this.findDevice(path);
|
|
805
|
+
this.assertHandleAvailable(currentDevice);
|
|
626
806
|
if (currentDevice.opened) {
|
|
627
807
|
const endpoints = this.deviceEndpoints.get(path);
|
|
628
808
|
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
629
809
|
try {
|
|
630
|
-
yield currentDevice.releaseInterface(ifaceNum);
|
|
810
|
+
yield this.runHandleOperation(() => currentDevice.releaseInterface(ifaceNum));
|
|
631
811
|
}
|
|
632
812
|
catch (releaseError) {
|
|
633
813
|
this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
|
|
634
814
|
}
|
|
635
|
-
|
|
815
|
+
this.assertHandleAvailable(currentDevice);
|
|
816
|
+
yield this.runHandleOperation(() => currentDevice.close());
|
|
636
817
|
}
|
|
637
818
|
}
|
|
638
819
|
catch (closeError) {
|
|
820
|
+
this.assertRunning();
|
|
821
|
+
if (this.isHandleOwnershipError(closeError))
|
|
822
|
+
throw closeError;
|
|
639
823
|
this.Log.debug('[WebUsbTransport] close device before retry error:', closeError);
|
|
640
824
|
}
|
|
641
825
|
yield this.getConnectedDevices();
|
|
@@ -677,6 +861,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
677
861
|
yield this.reconnectForPacketIoRetry(path, 'out', attempt, error);
|
|
678
862
|
}
|
|
679
863
|
catch (reconnectError) {
|
|
864
|
+
this.assertRunning();
|
|
865
|
+
if (this.isHandleOwnershipError(reconnectError))
|
|
866
|
+
throw reconnectError;
|
|
680
867
|
lastError = reconnectError;
|
|
681
868
|
this.Log.debug(`[WebUsbTransport] transferout reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
682
869
|
}
|
|
@@ -695,7 +882,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
695
882
|
const endpoints = this.deviceEndpoints.get(path);
|
|
696
883
|
const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
697
884
|
const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
885
|
+
this.assertHandleAvailable(device);
|
|
698
886
|
const result = yield device.transferOut(endpointOut, transferBuffer);
|
|
887
|
+
this.assertHandleAvailable(device);
|
|
699
888
|
if (result.status !== 'ok') {
|
|
700
889
|
return this.throwWebUsbIoError(path, 'transferOut', new Error(`transferOut status: ${String(result.status)}`));
|
|
701
890
|
}
|
|
@@ -716,7 +905,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
716
905
|
}
|
|
717
906
|
const endpoints = this.deviceEndpoints.get(path);
|
|
718
907
|
const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
908
|
+
this.assertHandleAvailable(device);
|
|
719
909
|
const result = yield device.transferIn(endpointIn, length);
|
|
910
|
+
this.assertHandleAvailable(device);
|
|
720
911
|
return this.getTransferInData(result);
|
|
721
912
|
}
|
|
722
913
|
catch (error) {
|
|
@@ -732,6 +923,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
732
923
|
yield this.reconnectForPacketIoRetry(path, 'in', attempt, error);
|
|
733
924
|
}
|
|
734
925
|
catch (reconnectError) {
|
|
926
|
+
this.assertRunning();
|
|
927
|
+
if (this.isHandleOwnershipError(reconnectError))
|
|
928
|
+
throw reconnectError;
|
|
735
929
|
lastError = reconnectError;
|
|
736
930
|
this.Log.debug(`[WebUsbTransport] transferin reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
737
931
|
}
|
|
@@ -749,7 +943,9 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
749
943
|
}
|
|
750
944
|
const endpoints = this.deviceEndpoints.get(path);
|
|
751
945
|
const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
946
|
+
this.assertHandleAvailable(device);
|
|
752
947
|
const result = yield device.transferIn(endpointIn, length);
|
|
948
|
+
this.assertHandleAvailable(device);
|
|
753
949
|
return this.getTransferInData(result);
|
|
754
950
|
});
|
|
755
951
|
}
|
|
@@ -935,6 +1131,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
935
1131
|
}
|
|
936
1132
|
finally {
|
|
937
1133
|
this.releaseIdentityProbeHandle(path);
|
|
1134
|
+
this.releaseNormalHandles(path);
|
|
938
1135
|
}
|
|
939
1136
|
this.deviceEndpoints.delete(path);
|
|
940
1137
|
});
|
package/dist/webusb.d.ts
CHANGED
|
@@ -19,6 +19,10 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
|
|
|
19
19
|
private staleProtocolPaths;
|
|
20
20
|
private acquiredPaths;
|
|
21
21
|
private identityProbeDevices;
|
|
22
|
+
private normalDevices;
|
|
23
|
+
private pendingHandleOperations;
|
|
24
|
+
private stopPromise?;
|
|
25
|
+
private identityProbeCleanupPaths;
|
|
22
26
|
private probedDeviceObjects;
|
|
23
27
|
private deviceEndpoints;
|
|
24
28
|
name: string;
|
|
@@ -33,6 +37,10 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
|
|
|
33
37
|
interfaceId: number;
|
|
34
38
|
constructor(identityProbe?: boolean);
|
|
35
39
|
init(logger: any, emitter?: EventEmitter): void;
|
|
40
|
+
stop(): Promise<void>;
|
|
41
|
+
private stopResources;
|
|
42
|
+
private assertRunning;
|
|
43
|
+
private runHandleOperation;
|
|
36
44
|
emitDeviceDisconnect(path: string, device?: USBDevice): void;
|
|
37
45
|
markProtocolStale(path: string): void;
|
|
38
46
|
configure(signedData: any): void;
|
|
@@ -50,6 +58,9 @@ export default class WebUsbTransport extends ProtocolV2UsbTransportBase<string>
|
|
|
50
58
|
private discoverEndpoints;
|
|
51
59
|
connectToDevice(path: string, first: boolean): Promise<undefined>;
|
|
52
60
|
private assertHandleAvailable;
|
|
61
|
+
private claimNormalHandle;
|
|
62
|
+
private releaseNormalHandles;
|
|
63
|
+
private isHandleOwnershipError;
|
|
53
64
|
private claimIdentityProbeHandle;
|
|
54
65
|
private releaseIdentityProbeHandle;
|
|
55
66
|
private closeOpenDevice;
|
package/dist/webusb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";;AACA,OAAO,SAAS,EAAE,EAQhB,0BAA0B,EAG3B,MAAM,wBAAwB,CAAC;AAahC,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.2.8-alpha.
|
|
3
|
+
"version": "1.2.8-alpha.17",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
"lint:fix": "eslint . --fix"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.8-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.8-alpha.
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.8-alpha.17",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.8-alpha.17"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@onekeyfe/hd-transport-electron": "1.2.8-alpha.
|
|
28
|
+
"@onekeyfe/hd-transport-electron": "1.2.8-alpha.17",
|
|
29
29
|
"@types/w3c-web-usb": "^1.0.6",
|
|
30
30
|
"@types/web-bluetooth": "^0.0.17"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "d7376861ee755a4c65226468a6b67ab2e6e9c55d"
|
|
33
33
|
}
|