UNPKG

trezor-link

Version:
593 lines (495 loc) 18.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _createClass = function () { function 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _desc, _value, _class; var _defered = require('../defered'); var _debugDecorator = require('../debug-decorator'); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object['ke' + 'ys'](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['define' + 'Property'](target, property, desc); desc = null; } return desc; } var pingBuffer = new TextEncoder().encode('PINGPING').buffer; var pongBuffer = new TextEncoder().encode('PONGPONG').buffer; // This is overcomplicated and could probable be simplier var ChromeUdpPlugin = (_class = function () { function ChromeUdpPlugin(portDiff) { _classCallCheck(this, ChromeUdpPlugin); this.name = 'ChromeUdpPlugin'; this.waiting = {}; this.buffered = {}; this.infos = {}; this.sockets = {}; this.version = "0.2.109"; this.debug = false; this.allowsWriteAndEnumerate = true; this.ports = []; this.requestNeeded = false; if (portDiff == null) { this.portDiff = 3; } else { this.portDiff = portDiff; } } // state of connections // for streaming of reading results _createClass(ChromeUdpPlugin, [{ key: 'init', value: function init(debug) { var _this = this; this.debug = !!debug; try { chrome.sockets.udp.onReceive.addListener(function (_ref) { var socketId = _ref.socketId, data = _ref.data; _this._udpListener(socketId, data); }); return Promise.resolve(); } catch (e) { // if not Chrome, not sockets etc, this will reject return Promise.reject(e); } } }, { key: 'setPorts', value: function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(ports) { var oldPorts, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, port, _socket, socket2; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!(ports.length > this.portDiff)) { _context.next = 2; break; } throw new Error('Too many ports. Max ' + this.portDiff + ' allowed.'); case 2: oldPorts = this.ports; _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; _context.prev = 6; _iterator = oldPorts[Symbol.iterator](); case 8: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { _context.next = 21; break; } port = _step.value; _socket = this.sockets[(port + this.portDiff).toString()]; if (!_socket) { _context.next = 14; break; } _context.next = 14; return this._udpDisconnect(parseInt(_socket)); case 14: socket2 = this.sockets[(port + this.portDiff * 2).toString()]; if (!socket2) { _context.next = 18; break; } _context.next = 18; return this._udpDisconnect(parseInt(socket2)); case 18: _iteratorNormalCompletion = true; _context.next = 8; break; case 21: _context.next = 27; break; case 23: _context.prev = 23; _context.t0 = _context['catch'](6); _didIteratorError = true; _iteratorError = _context.t0; case 27: _context.prev = 27; _context.prev = 28; if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } case 30: _context.prev = 30; if (!_didIteratorError) { _context.next = 33; break; } throw _iteratorError; case 33: return _context.finish(30); case 34: return _context.finish(27); case 35: this.ports = ports; case 36: case 'end': return _context.stop(); } } }, _callee, this, [[6, 23, 27, 35], [28,, 30, 34]]); })); function setPorts(_x) { return _ref2.apply(this, arguments); } return setPorts; }() }, { key: 'enumerate', value: function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() { var res, wrongBufferError, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, port, _socket2, _portIn, socketS, resBuffer, _socket3; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: res = []; wrongBufferError = new Error(); _iteratorNormalCompletion2 = true; _didIteratorError2 = false; _iteratorError2 = undefined; _context2.prev = 5; _iterator2 = this.ports[Symbol.iterator](); case 7: if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { _context2.next = 45; break; } port = _step2.value; _context2.prev = 9; _socket2 = void 0; _portIn = (port + this.portDiff).toString(); socketS = this.sockets[_portIn]; if (!socketS) { _context2.next = 17; break; } _socket2 = parseInt(socketS); _context2.next = 20; break; case 17: _context2.next = 19; return this._udpConnect(port, this.portDiff); case 19: _socket2 = _context2.sent; case 20: _context2.prev = 20; _context2.next = 23; return this._udpLowSend(_socket2, pingBuffer); case 23: _context2.next = 25; return Promise.race([(0, _defered.rejectTimeoutPromise)(1000, wrongBufferError), this._udpLowReceive(_socket2, 80)] // 80 is "P" in "PONG" ); case 25: resBuffer = _context2.sent; if (arraybufferEqual(pongBuffer, resBuffer)) { _context2.next = 28; break; } throw wrongBufferError; case 28: res.push({ path: port.toString() }); _context2.next = 38; break; case 31: _context2.prev = 31; _context2.t0 = _context2['catch'](20); if (!(_context2.t0 === wrongBufferError)) { _context2.next = 38; break; } _socket3 = this.sockets[(port + this.portDiff).toString()]; if (!_socket3) { _context2.next = 38; break; } _context2.next = 38; return this._udpDisconnect(parseInt(_socket3)); case 38: _context2.next = 42; break; case 40: _context2.prev = 40; _context2.t1 = _context2['catch'](9); case 42: _iteratorNormalCompletion2 = true; _context2.next = 7; break; case 45: _context2.next = 51; break; case 47: _context2.prev = 47; _context2.t2 = _context2['catch'](5); _didIteratorError2 = true; _iteratorError2 = _context2.t2; case 51: _context2.prev = 51; _context2.prev = 52; if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } case 54: _context2.prev = 54; if (!_didIteratorError2) { _context2.next = 57; break; } throw _iteratorError2; case 57: return _context2.finish(54); case 58: return _context2.finish(51); case 59: return _context2.abrupt('return', res); case 60: case 'end': return _context2.stop(); } } }, _callee2, this, [[5, 47, 51, 59], [9, 40], [20, 31], [52,, 54, 58]]); })); function enumerate() { return _ref3.apply(this, arguments); } return enumerate; }() }, { key: 'send', value: function send(device, session, data) { var socket = parseInt(session); if (isNaN(socket)) { return Promise.reject(new Error('Session not a number')); } return this._udpSend(socket, data); } }, { key: 'receive', value: function receive(device, session) { var socket = parseInt(session); if (isNaN(socket)) { return Promise.reject(new Error('Session not a number')); } return this._udpReceive(socket); } }, { key: 'connect', value: function connect(device) { var port = parseInt(device); if (isNaN(port)) { return Promise.reject(new Error('Device not a number')); } var socket = this.sockets[(port + this.portDiff).toString()]; if (socket == null) { return Promise.reject(new Error('Unknown device ' + device)); } return Promise.resolve(socket); } }, { key: 'disconnect', value: function disconnect(path, session) { var socket = parseInt(session); if (isNaN(socket)) { return Promise.reject(new Error('Session not a number')); } return Promise.resolve(); } }, { key: '_udpDisconnect', value: function _udpDisconnect(socketId) { var _this2 = this; return new Promise(function (resolve, reject) { try { chrome.sockets.udp.close(socketId, function () { if (chrome.runtime.lastError) { reject(new Error('Disconnect error ' + JSON.stringify(chrome.runtime.lastError))); } else { var info = _this2.infos[socketId.toString()]; delete _this2.infos[socketId.toString()]; if (info != null) { delete _this2.sockets[info.portIn.toString()]; } resolve(); } }); } catch (e) { reject(e); } }); } }, { key: '_udpConnect', value: function _udpConnect(port, diff) { var _this3 = this; var address = '127.0.0.1'; return new Promise(function (resolve, reject) { try { chrome.sockets.udp.create({}, function (_ref4) { var socketId = _ref4.socketId; if (chrome.runtime.lastError) { reject(new Error('Connect error ' + JSON.stringify(chrome.runtime.lastError))); } else { try { chrome.sockets.udp.bind(socketId, '127.0.0.1', port + diff, function (result) { if (chrome.runtime.lastError) { reject(new Error('Bind error ' + JSON.stringify(chrome.runtime.lastError))); } else { if (result >= 0) { var _portIn2 = port + diff; _this3.infos[socketId.toString()] = { address: address, portOut: port, portIn: _portIn2 }; _this3.sockets[_portIn2.toString()] = socketId.toString(); resolve(socketId); } else { reject('Cannot create socket, error: ' + result); } } }); } catch (e) { reject(e); } } }); } catch (e) { reject(e); } }); } }, { key: '_udpReceive', value: function _udpReceive(socketId) { return this._udpLowReceive(socketId, 63).then(function (data) { var dataView = new Uint8Array(data); if (dataView[0] !== 63) { throw new Error('Invalid data; first byte should be 63, is ' + dataView[0]); } return data.slice(1); }); } }, { key: '_udpLowReceive', value: function _udpLowReceive(socketId, type) { var id = socketId.toString(); var socketPlusType = id + '-' + type; if (this.buffered[socketPlusType] != null) { var res = this.buffered[socketPlusType].shift(); if (this.buffered[socketPlusType].length === 0) { delete this.buffered[socketPlusType]; } return Promise.resolve(res); } if (this.waiting[socketPlusType] != null) { return Promise.reject('Something else already listening on socketId ' + socketPlusType); } var d = (0, _defered.create)(); this.waiting[socketPlusType] = d; return d.promise; } }, { key: '_udpSend', value: function _udpSend(socketId, data) { var sendDataV = new Uint8Array(64); sendDataV[0] = 63; sendDataV.set(new Uint8Array(data), 1); var sendData = sendDataV.buffer; return this._udpLowSend(socketId, sendData); } }, { key: '_udpLowSend', value: function _udpLowSend(socketId, sendData) { var id = socketId.toString(); var info = this.infos[id]; if (info == null) { return Promise.reject('Socket ' + socketId + ' does not exist'); } return new Promise(function (resolve, reject) { try { chrome.sockets.udp.send(socketId, sendData, info.address, info.portOut, function (_ref5) { var resultCode = _ref5.resultCode; if (chrome.runtime.lastError) { reject(new Error('Send error ' + JSON.stringify(chrome.runtime.lastError))); } else { if (resultCode >= 0) { resolve(); } else { reject('Cannot send, error: ' + resultCode); } } }); } catch (e) { reject(e); } }); } }, { key: '_udpListener', value: function _udpListener(socketId, data) { var id = socketId.toString(); var dataArr = new Uint8Array(data); var type = dataArr[0]; var socketPlusType = id + '-' + type; var d = this.waiting[socketPlusType]; if (d != null) { d.resolve(data); delete this.waiting[socketPlusType]; } else { if (this.infos[socketPlusType] != null) { if (this.buffered[socketPlusType] == null) { this.buffered[socketPlusType] = []; } this.buffered[socketPlusType].push(data); } } } }, { key: 'requestDevice', value: function requestDevice() { return Promise.reject(); } }]); return ChromeUdpPlugin; }(), (_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); // from https://github.com/wbinnssmith/arraybuffer-equal // (c) 2015 Will Binns-Smith. Licensed MIT. exports.default = ChromeUdpPlugin; function arraybufferEqual(buf1, buf2) { if (buf1 === buf2) { return true; } if (buf1.byteLength !== buf2.byteLength) { return false; } var view1 = new DataView(buf1); var view2 = new DataView(buf2); var i = buf1.byteLength; while (i--) { if (view1.getUint8(i) !== view2.getUint8(i)) { return false; } } return true; } module.exports = exports['default'];