UNPKG

21 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports["default"] = void 0;
7
8var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
10var _events = _interopRequireDefault(require("events"));
11
12var _debugDecorator = require("../debug-decorator");
13
14var _class, _temp;
15
16function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
17
18function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
19
20function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
21
22function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
23
24function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
25
26function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
27
28function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
29
30function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; }
31
32var T1HID_VENDOR = 0x534c;
33var TREZOR_DESCS = [// TREZOR v1
34// won't get opened, but we can show error at least
35{
36 vendorId: 0x534c,
37 productId: 0x0001
38}, // TREZOR webusb Bootloader
39{
40 vendorId: 0x1209,
41 productId: 0x53c0
42}, // TREZOR webusb Firmware
43{
44 vendorId: 0x1209,
45 productId: 0x53c1
46}];
47var CONFIGURATION_ID = 1;
48var INTERFACE_ID = 0;
49var ENDPOINT_ID = 1;
50var DEBUG_INTERFACE_ID = 1;
51var DEBUG_ENDPOINT_ID = 2;
52var WebUsbPlugin = (_class = (_temp =
53/*#__PURE__*/
54function () {
55 function WebUsbPlugin() {
56 _classCallCheck(this, WebUsbPlugin);
57
58 this.name = "WebUsbPlugin";
59 this.version = "1.6.5";
60 this.debug = false;
61 this.allowsWriteAndEnumerate = true;
62 this.configurationId = CONFIGURATION_ID;
63 this.normalInterfaceId = INTERFACE_ID;
64 this.normalEndpointId = ENDPOINT_ID;
65 this.debugInterfaceId = DEBUG_INTERFACE_ID;
66 this.debugEndpointId = DEBUG_ENDPOINT_ID;
67 this.unreadableHidDevice = false;
68 this.unreadableHidDeviceChange = new _events["default"]();
69 this._lastDevices = [];
70 this.requestNeeded = true;
71 }
72
73 _createClass(WebUsbPlugin, [{
74 key: "init",
75 value: function () {
76 var _init = _asyncToGenerator(
77 /*#__PURE__*/
78 _regenerator["default"].mark(function _callee(debug) {
79 var usb;
80 return _regenerator["default"].wrap(function _callee$(_context) {
81 while (1) {
82 switch (_context.prev = _context.next) {
83 case 0:
84 this.debug = !!debug; // $FlowIssue
85
86 usb = navigator.usb;
87
88 if (!(usb == null)) {
89 _context.next = 6;
90 break;
91 }
92
93 throw new Error("WebUSB is not available on this browser.");
94
95 case 6:
96 this.usb = usb;
97
98 case 7:
99 case "end":
100 return _context.stop();
101 }
102 }
103 }, _callee, this);
104 }));
105
106 function init(_x) {
107 return _init.apply(this, arguments);
108 }
109
110 return init;
111 }()
112 }, {
113 key: "_deviceHasDebugLink",
114 value: function _deviceHasDebugLink(device) {
115 try {
116 var iface = device.configurations[0].interfaces[DEBUG_INTERFACE_ID].alternates[0];
117 return iface.interfaceClass === 255 && iface.endpoints[0].endpointNumber === DEBUG_ENDPOINT_ID;
118 } catch (e) {
119 return false;
120 }
121 }
122 }, {
123 key: "_deviceIsHid",
124 value: function _deviceIsHid(device) {
125 return device.vendorId === T1HID_VENDOR;
126 }
127 }, {
128 key: "_listDevices",
129 value: function () {
130 var _listDevices2 = _asyncToGenerator(
131 /*#__PURE__*/
132 _regenerator["default"].mark(function _callee2() {
133 var _this = this;
134
135 var bootloaderId, devices, trezorDevices, hidDevices, nonHidDevices, oldUnreadableHidDevice;
136 return _regenerator["default"].wrap(function _callee2$(_context2) {
137 while (1) {
138 switch (_context2.prev = _context2.next) {
139 case 0:
140 bootloaderId = 0;
141 _context2.next = 3;
142 return this.usb.getDevices();
143
144 case 3:
145 devices = _context2.sent;
146 trezorDevices = devices.filter(function (dev) {
147 var isTrezor = TREZOR_DESCS.some(function (desc) {
148 return dev.vendorId === desc.vendorId && dev.productId === desc.productId;
149 });
150 return isTrezor;
151 });
152 hidDevices = trezorDevices.filter(function (dev) {
153 return _this._deviceIsHid(dev);
154 });
155 nonHidDevices = trezorDevices.filter(function (dev) {
156 return !_this._deviceIsHid(dev);
157 });
158 this._lastDevices = nonHidDevices.map(function (device) {
159 // path is just serial number
160 // more bootloaders => number them, hope for the best
161 var serialNumber = device.serialNumber;
162 var path = serialNumber == null || serialNumber === "" ? "bootloader" : serialNumber;
163
164 if (path === "bootloader") {
165 bootloaderId++;
166 path = path + bootloaderId;
167 }
168
169 var debug = _this._deviceHasDebugLink(device);
170
171 return {
172 path: path,
173 device: device,
174 debug: debug
175 };
176 });
177 oldUnreadableHidDevice = this.unreadableHidDevice;
178 this.unreadableHidDevice = hidDevices.length > 0;
179
180 if (oldUnreadableHidDevice !== this.unreadableHidDevice) {
181 this.unreadableHidDeviceChange.emit("change");
182 }
183
184 return _context2.abrupt("return", this._lastDevices);
185
186 case 12:
187 case "end":
188 return _context2.stop();
189 }
190 }
191 }, _callee2, this);
192 }));
193
194 function _listDevices() {
195 return _listDevices2.apply(this, arguments);
196 }
197
198 return _listDevices;
199 }()
200 }, {
201 key: "enumerate",
202 value: function () {
203 var _enumerate = _asyncToGenerator(
204 /*#__PURE__*/
205 _regenerator["default"].mark(function _callee3() {
206 return _regenerator["default"].wrap(function _callee3$(_context3) {
207 while (1) {
208 switch (_context3.prev = _context3.next) {
209 case 0:
210 _context3.next = 2;
211 return this._listDevices();
212
213 case 2:
214 _context3.t0 = function (info) {
215 return {
216 path: info.path,
217 debug: info.debug
218 };
219 };
220
221 return _context3.abrupt("return", _context3.sent.map(_context3.t0));
222
223 case 4:
224 case "end":
225 return _context3.stop();
226 }
227 }
228 }, _callee3, this);
229 }));
230
231 function enumerate() {
232 return _enumerate.apply(this, arguments);
233 }
234
235 return enumerate;
236 }()
237 }, {
238 key: "_findDevice",
239 value: function () {
240 var _findDevice2 = _asyncToGenerator(
241 /*#__PURE__*/
242 _regenerator["default"].mark(function _callee4(path) {
243 var deviceO;
244 return _regenerator["default"].wrap(function _callee4$(_context4) {
245 while (1) {
246 switch (_context4.prev = _context4.next) {
247 case 0:
248 deviceO = this._lastDevices.find(function (d) {
249 return d.path === path;
250 });
251
252 if (!(deviceO == null)) {
253 _context4.next = 3;
254 break;
255 }
256
257 throw new Error("Action was interrupted.");
258
259 case 3:
260 return _context4.abrupt("return", deviceO.device);
261
262 case 4:
263 case "end":
264 return _context4.stop();
265 }
266 }
267 }, _callee4, this);
268 }));
269
270 function _findDevice(_x2) {
271 return _findDevice2.apply(this, arguments);
272 }
273
274 return _findDevice;
275 }()
276 }, {
277 key: "send",
278 value: function () {
279 var _send = _asyncToGenerator(
280 /*#__PURE__*/
281 _regenerator["default"].mark(function _callee5(path, data, debug) {
282 var device, newArray, endpoint;
283 return _regenerator["default"].wrap(function _callee5$(_context5) {
284 while (1) {
285 switch (_context5.prev = _context5.next) {
286 case 0:
287 _context5.next = 2;
288 return this._findDevice(path);
289
290 case 2:
291 device = _context5.sent;
292 newArray = new Uint8Array(64);
293 newArray[0] = 63;
294 newArray.set(new Uint8Array(data), 1);
295
296 if (device.opened) {
297 _context5.next = 9;
298 break;
299 }
300
301 _context5.next = 9;
302 return this.connect(path, debug, false);
303
304 case 9:
305 endpoint = debug ? this.debugEndpointId : this.normalEndpointId;
306 return _context5.abrupt("return", device.transferOut(endpoint, newArray).then(function () {}));
307
308 case 11:
309 case "end":
310 return _context5.stop();
311 }
312 }
313 }, _callee5, this);
314 }));
315
316 function send(_x3, _x4, _x5) {
317 return _send.apply(this, arguments);
318 }
319
320 return send;
321 }()
322 }, {
323 key: "receive",
324 value: function () {
325 var _receive = _asyncToGenerator(
326 /*#__PURE__*/
327 _regenerator["default"].mark(function _callee6(path, debug) {
328 var device, endpoint, res;
329 return _regenerator["default"].wrap(function _callee6$(_context6) {
330 while (1) {
331 switch (_context6.prev = _context6.next) {
332 case 0:
333 _context6.next = 2;
334 return this._findDevice(path);
335
336 case 2:
337 device = _context6.sent;
338 endpoint = debug ? this.debugEndpointId : this.normalEndpointId;
339 _context6.prev = 4;
340
341 if (device.opened) {
342 _context6.next = 8;
343 break;
344 }
345
346 _context6.next = 8;
347 return this.connect(path, debug, false);
348
349 case 8:
350 _context6.next = 10;
351 return device.transferIn(endpoint, 64);
352
353 case 10:
354 res = _context6.sent;
355
356 if (!(res.data.byteLength === 0)) {
357 _context6.next = 13;
358 break;
359 }
360
361 return _context6.abrupt("return", this.receive(path, debug));
362
363 case 13:
364 return _context6.abrupt("return", res.data.buffer.slice(1));
365
366 case 16:
367 _context6.prev = 16;
368 _context6.t0 = _context6["catch"](4);
369
370 if (!(_context6.t0.message === "Device unavailable.")) {
371 _context6.next = 22;
372 break;
373 }
374
375 throw new Error("Action was interrupted.");
376
377 case 22:
378 throw _context6.t0;
379
380 case 23:
381 case "end":
382 return _context6.stop();
383 }
384 }
385 }, _callee6, this, [[4, 16]]);
386 }));
387
388 function receive(_x6, _x7) {
389 return _receive.apply(this, arguments);
390 }
391
392 return receive;
393 }()
394 }, {
395 key: "connect",
396 value: function () {
397 var _connect = _asyncToGenerator(
398 /*#__PURE__*/
399 _regenerator["default"].mark(function _callee7(path, debug, first) {
400 var _this2 = this;
401
402 var _loop, i, _ret;
403
404 return _regenerator["default"].wrap(function _callee7$(_context8) {
405 while (1) {
406 switch (_context8.prev = _context8.next) {
407 case 0:
408 _loop =
409 /*#__PURE__*/
410 _regenerator["default"].mark(function _loop(i) {
411 return _regenerator["default"].wrap(function _loop$(_context7) {
412 while (1) {
413 switch (_context7.prev = _context7.next) {
414 case 0:
415 if (!(i > 0)) {
416 _context7.next = 3;
417 break;
418 }
419
420 _context7.next = 3;
421 return new Promise(function (resolve) {
422 return setTimeout(function () {
423 return resolve();
424 }, i * 200);
425 });
426
427 case 3:
428 _context7.prev = 3;
429 _context7.next = 6;
430 return _this2._connectIn(path, debug, first);
431
432 case 6:
433 _context7.t0 = _context7.sent;
434 return _context7.abrupt("return", {
435 v: _context7.t0
436 });
437
438 case 10:
439 _context7.prev = 10;
440 _context7.t1 = _context7["catch"](3);
441
442 if (!(i === 4)) {
443 _context7.next = 14;
444 break;
445 }
446
447 throw _context7.t1;
448
449 case 14:
450 case "end":
451 return _context7.stop();
452 }
453 }
454 }, _loop, null, [[3, 10]]);
455 });
456 i = 0;
457
458 case 2:
459 if (!(i < 5)) {
460 _context8.next = 10;
461 break;
462 }
463
464 return _context8.delegateYield(_loop(i), "t0", 4);
465
466 case 4:
467 _ret = _context8.t0;
468
469 if (!(_typeof(_ret) === "object")) {
470 _context8.next = 7;
471 break;
472 }
473
474 return _context8.abrupt("return", _ret.v);
475
476 case 7:
477 i++;
478 _context8.next = 2;
479 break;
480
481 case 10:
482 case "end":
483 return _context8.stop();
484 }
485 }
486 }, _callee7);
487 }));
488
489 function connect(_x8, _x9, _x10) {
490 return _connect.apply(this, arguments);
491 }
492
493 return connect;
494 }()
495 }, {
496 key: "_connectIn",
497 value: function () {
498 var _connectIn2 = _asyncToGenerator(
499 /*#__PURE__*/
500 _regenerator["default"].mark(function _callee8(path, debug, first) {
501 var device, chromeOS, interfaceId;
502 return _regenerator["default"].wrap(function _callee8$(_context9) {
503 while (1) {
504 switch (_context9.prev = _context9.next) {
505 case 0:
506 _context9.next = 2;
507 return this._findDevice(path);
508
509 case 2:
510 device = _context9.sent;
511 _context9.next = 5;
512 return device.open();
513
514 case 5:
515 if (!first) {
516 _context9.next = 13;
517 break;
518 }
519
520 _context9.next = 8;
521 return device.selectConfiguration(this.configurationId);
522
523 case 8:
524 if (!(typeof navigator !== "undefined")) {
525 _context9.next = 13;
526 break;
527 }
528
529 chromeOS = /\bCrOS\b/.test(navigator.userAgent);
530
531 if (chromeOS) {
532 _context9.next = 13;
533 break;
534 }
535
536 _context9.next = 13;
537 return device.reset();
538
539 case 13:
540 interfaceId = debug ? this.debugInterfaceId : this.normalInterfaceId;
541 _context9.next = 16;
542 return device.claimInterface(interfaceId);
543
544 case 16:
545 case "end":
546 return _context9.stop();
547 }
548 }
549 }, _callee8, this);
550 }));
551
552 function _connectIn(_x11, _x12, _x13) {
553 return _connectIn2.apply(this, arguments);
554 }
555
556 return _connectIn;
557 }()
558 }, {
559 key: "disconnect",
560 value: function () {
561 var _disconnect = _asyncToGenerator(
562 /*#__PURE__*/
563 _regenerator["default"].mark(function _callee9(path, debug, last) {
564 var device, interfaceId;
565 return _regenerator["default"].wrap(function _callee9$(_context10) {
566 while (1) {
567 switch (_context10.prev = _context10.next) {
568 case 0:
569 _context10.next = 2;
570 return this._findDevice(path);
571
572 case 2:
573 device = _context10.sent;
574 interfaceId = debug ? this.debugInterfaceId : this.normalInterfaceId;
575 _context10.next = 6;
576 return device.releaseInterface(interfaceId);
577
578 case 6:
579 if (!last) {
580 _context10.next = 9;
581 break;
582 }
583
584 _context10.next = 9;
585 return device.close();
586
587 case 9:
588 case "end":
589 return _context10.stop();
590 }
591 }
592 }, _callee9, this);
593 }));
594
595 function disconnect(_x14, _x15, _x16) {
596 return _disconnect.apply(this, arguments);
597 }
598
599 return disconnect;
600 }()
601 }, {
602 key: "requestDevice",
603 value: function () {
604 var _requestDevice = _asyncToGenerator(
605 /*#__PURE__*/
606 _regenerator["default"].mark(function _callee10() {
607 return _regenerator["default"].wrap(function _callee10$(_context11) {
608 while (1) {
609 switch (_context11.prev = _context11.next) {
610 case 0:
611 _context11.next = 2;
612 return this.usb.requestDevice({
613 filters: TREZOR_DESCS
614 });
615
616 case 2:
617 case "end":
618 return _context11.stop();
619 }
620 }
621 }, _callee10, this);
622 }));
623
624 function requestDevice() {
625 return _requestDevice.apply(this, arguments);
626 }
627
628 return requestDevice;
629 }()
630 }]);
631
632 return WebUsbPlugin;
633}(), _temp), (_applyDecoratedDescriptor(_class.prototype, "init", [_debugDecorator.debugInOut], Object.getOwnPropertyDescriptor(_class.prototype, "init"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "connect", [_debugDecorator.debugInOut], Object.getOwnPropertyDescriptor(_class.prototype, "connect"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "disconnect", [_debugDecorator.debugInOut], Object.getOwnPropertyDescriptor(_class.prototype, "disconnect"), _class.prototype)), _class);
634exports["default"] = WebUsbPlugin;
635module.exports = exports.default;
\No newline at end of file