Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ledgerhq/hw-transport-node-hid

Package Overview
Dependencies
Maintainers
5
Versions
399
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ledgerhq/hw-transport-node-hid - npm Package Compare versions

Comparing version 1.1.1-beta.068e2a14 to 1.1.2-beta.068e2a14

52

lib/listenDevices.js

@@ -15,14 +15,10 @@ "use strict";

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var myEE = new _events2.default();
const myEE = new _events2.default();
myEE.setMaxListeners(0);
var timeoutDetection = null;
var isListenDevices = false;
let timeoutDetection = null;
let isListenDevices = false;
exports.default = {
start: function start() {
var delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
start: (delay = 100) => {
if (isListenDevices) {

@@ -34,31 +30,17 @@ return;

var listDevices = (0, _nodeHid.devices)();
let listDevices = (0, _nodeHid.devices)();
var flatDevice = function flatDevice(device) {
return device.path;
};
const flatDevice = device => device.path;
var getFlatDevices = function getFlatDevices() {
return [].concat(_toConsumableArray(new Set((0, _nodeHid.devices)().map(function (device) {
return flatDevice(device);
}))));
};
var getDeviceByPath = function getDeviceByPath(ids) {
return listDevices.find(function (device) {
return flatDevice(device) === ids;
});
};
const getFlatDevices = () => [...new Set((0, _nodeHid.devices)().map(device => flatDevice(device)))];
const getDeviceByPath = ids => listDevices.find(device => flatDevice(device) === ids);
var lastDevices = getFlatDevices();
let lastDevices = getFlatDevices();
var checkDevices = function checkDevices() {
timeoutDetection = setTimeout(function () {
var currentDevices = getFlatDevices();
const checkDevices = () => {
timeoutDetection = setTimeout(() => {
const currentDevices = getFlatDevices();
var addDevice = currentDevices.find(function (device) {
return !lastDevices.includes(device);
});
var removeDevice = lastDevices.find(function (device) {
return !currentDevices.includes(device);
});
const addDevice = currentDevices.find(device => !lastDevices.includes(device));
const removeDevice = lastDevices.find(device => !currentDevices.includes(device));

@@ -72,5 +54,3 @@ if (addDevice) {

myEE.emit("remove", getDeviceByPath(removeDevice));
listDevices = listDevices.filter(function (device) {
return flatDevice(device) !== removeDevice;
});
listDevices = listDevices.filter(device => flatDevice(device) !== removeDevice);
}

@@ -86,3 +66,3 @@

},
stop: function stop() {
stop: () => {
isListenDevices = false;

@@ -89,0 +69,0 @@

@@ -7,4 +7,2 @@ "use strict";

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 _nodeHid = require("node-hid");

@@ -26,13 +24,6 @@

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
// FIXME drop
function defer() {
var resolve = void 0,
reject = void 0;
var promise = new Promise(function (success, failure) {
let resolve, reject;
let promise = new Promise(function (success, failure) {
resolve = success;

@@ -42,3 +33,3 @@ reject = failure;

if (!resolve || !reject) throw "defer() error"; // this never happens and is just to make flow happy
return { promise: promise, resolve: resolve, reject: reject };
return { promise, resolve, reject };
}

@@ -53,33 +44,47 @@

*/
class TransportNodeHid extends _hwTransport2.default {
var TransportNodeHid = function (_Transport) {
_inherits(TransportNodeHid, _Transport);
constructor(device, ledgerTransport = true, timeout = 0, debug = false) {
super();
this.device = device;
this.ledgerTransport = ledgerTransport;
this.timeout = timeout;
this.exchangeStack = [];
this.debug = debug;
}
function TransportNodeHid(device) {
var ledgerTransport = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var debug = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
static open(path) {
return _asyncToGenerator(function* () {
return Promise.resolve(new TransportNodeHid(new _nodeHid2.default.HID(path)));
})();
}
_classCallCheck(this, TransportNodeHid);
var _this = _possibleConstructorReturn(this, (TransportNodeHid.__proto__ || Object.getPrototypeOf(TransportNodeHid)).call(this));
_this.device = device;
_this.ledgerTransport = ledgerTransport;
_this.timeout = timeout;
_this.exchangeStack = [];
_this.debug = debug;
return _this;
/**
* static function to create a new Transport from the first connected Ledger device found in USB
*/
static create(timeout, debug) {
return TransportNodeHid.list().then(result => {
if (result.length === 0) {
throw "No device found";
}
return new TransportNodeHid(new _nodeHid2.default.HID(result[0]), true, timeout, debug);
});
}
_createClass(TransportNodeHid, [{
key: "exchange",
value: function exchange(apduHex, statusList) {
var _this2 = this;
exchange(apduHex, statusList) {
function ledgerWrap(channel, command, packetSize) {
let sequenceIdx = 0;
let offset = 0;
function ledgerWrap(channel, command, packetSize) {
var sequenceIdx = 0;
var offset = 0;
var tmp = Buffer.alloc(7);
let tmp = Buffer.alloc(7);
tmp.writeUInt16BE(channel, 0);
tmp[2] = 0x05; // TAG_APDU
tmp.writeUInt16BE(sequenceIdx, 3);
sequenceIdx++;
tmp.writeUInt16BE(command.length, 5);
let blockSize = command.length > packetSize - 7 ? packetSize - 7 : command.length;
let result = Buffer.concat([tmp, command.slice(offset, offset + blockSize)], blockSize + 7);
offset += blockSize;
while (offset !== command.length) {
tmp = Buffer.alloc(5);
tmp.writeUInt16BE(channel, 0);

@@ -89,25 +94,43 @@ tmp[2] = 0x05; // TAG_APDU

sequenceIdx++;
tmp.writeUInt16BE(command.length, 5);
var blockSize = command.length > packetSize - 7 ? packetSize - 7 : command.length;
var result = Buffer.concat([tmp, command.slice(offset, offset + blockSize)], blockSize + 7);
blockSize = command.length - offset > packetSize - 5 ? packetSize - 5 : command.length - offset;
result = Buffer.concat([result, tmp, command.slice(offset, offset + blockSize)], result.length + blockSize + 5);
offset += blockSize;
while (offset !== command.length) {
tmp = Buffer.alloc(5);
tmp.writeUInt16BE(channel, 0);
tmp[2] = 0x05; // TAG_APDU
tmp.writeUInt16BE(sequenceIdx, 3);
sequenceIdx++;
blockSize = command.length - offset > packetSize - 5 ? packetSize - 5 : command.length - offset;
result = Buffer.concat([result, tmp, command.slice(offset, offset + blockSize)], result.length + blockSize + 5);
offset += blockSize;
}
return result;
}
return result;
}
function ledgerUnwrap(channel, data, packetSize) {
var offset = 0;
var responseLength = void 0;
var sequenceIdx = 0;
var response = void 0;
if (typeof data === "undefined" || data.length < 7 + 5) {
function ledgerUnwrap(channel, data, packetSize) {
let offset = 0;
let responseLength;
let sequenceIdx = 0;
let response;
if (typeof data === "undefined" || data.length < 7 + 5) {
return;
}
if (data[offset++] !== channel >> 8) {
throw "Invalid channel;";
}
if (data[offset++] !== (channel & 0xff)) {
throw "Invalid channel";
}
if (data[offset++] !== 0x05) {
throw "Invalid tag";
}
if (data[offset++] !== 0x00) {
throw "Invalid sequence";
}
if (data[offset++] !== 0x00) {
throw "Invalid sequence";
}
responseLength = (data[offset++] & 0xff) << 8;
responseLength |= data[offset++] & 0xff;
if (data.length < 7 + responseLength) {
return;
}
let blockSize = responseLength > packetSize - 7 ? packetSize - 7 : responseLength;
response = data.slice(offset, offset + blockSize);
offset += blockSize;
while (response.length !== responseLength) {
sequenceIdx++;
if (offset === data.length) {
return;

@@ -124,318 +147,212 @@ }

}
if (data[offset++] !== 0x00) {
if (data[offset++] !== sequenceIdx >> 8) {
throw "Invalid sequence";
}
if (data[offset++] !== 0x00) {
if (data[offset++] !== (sequenceIdx & 0xff)) {
throw "Invalid sequence";
}
responseLength = (data[offset++] & 0xff) << 8;
responseLength |= data[offset++] & 0xff;
if (data.length < 7 + responseLength) {
blockSize = responseLength - response.length > packetSize - 5 ? packetSize - 5 : responseLength - response.length;
if (blockSize > data.length - offset) {
return;
}
var blockSize = responseLength > packetSize - 7 ? packetSize - 7 : responseLength;
response = data.slice(offset, offset + blockSize);
response = Buffer.concat([response, data.slice(offset, offset + blockSize)], response.length + blockSize);
offset += blockSize;
while (response.length !== responseLength) {
sequenceIdx++;
if (offset === data.length) {
return;
}
if (data[offset++] !== channel >> 8) {
throw "Invalid channel;";
}
if (data[offset++] !== (channel & 0xff)) {
throw "Invalid channel";
}
if (data[offset++] !== 0x05) {
throw "Invalid tag";
}
if (data[offset++] !== sequenceIdx >> 8) {
throw "Invalid sequence";
}
if (data[offset++] !== (sequenceIdx & 0xff)) {
throw "Invalid sequence";
}
blockSize = responseLength - response.length > packetSize - 5 ? packetSize - 5 : responseLength - response.length;
if (blockSize > data.length - offset) {
return;
}
response = Buffer.concat([response, data.slice(offset, offset + blockSize)], response.length + blockSize);
offset += blockSize;
}
return response;
}
return response;
}
var apdu = Buffer.from(apduHex, "hex");
const apdu = Buffer.from(apduHex, "hex");
var deferred = defer();
var exchangeTimeout = void 0;
var transport = void 0;
if (!this.ledgerTransport) {
transport = apdu;
} else {
transport = ledgerWrap(0x0101, apdu, 64);
}
const deferred = defer();
let exchangeTimeout;
let transport;
if (!this.ledgerTransport) {
transport = apdu;
} else {
transport = ledgerWrap(0x0101, apdu, 64);
}
if (this.timeout !== 0) {
exchangeTimeout = setTimeout(function () {
// Node.js supports timeouts
deferred.reject("timeout");
}, this.timeout);
}
if (this.timeout !== 0) {
exchangeTimeout = setTimeout(() => {
// Node.js supports timeouts
deferred.reject("timeout");
}, this.timeout);
}
// enter the exchange wait list
this.exchangeStack.push(deferred);
// enter the exchange wait list
this.exchangeStack.push(deferred);
if (this.exchangeStack.length === 1) {
var processNextExchange = function processNextExchange() {
// don't pop it now, to avoid multiple at once
var deferred = _this2.exchangeStack[0];
if (this.exchangeStack.length === 1) {
const processNextExchange = () => {
// don't pop it now, to avoid multiple at once
const deferred = this.exchangeStack[0];
var send = function send(content) {
if (_this2.debug) {
console.log("=>" + content.toString("hex"));
const send = content => {
if (this.debug) {
console.log("=>" + content.toString("hex"));
}
const data = [0x00];
for (let i = 0; i < content.length; i++) {
data.push(content[i]);
}
this.device.write(data);
return Promise.resolve(content.length);
};
const recv = () => new Promise((resolve, reject) => this.device.read((err, res) => {
if (err || !res) reject(err);else {
const buffer = Buffer.from(res);
if (this.debug) {
console.log("<=" + buffer.toString("hex"));
}
var data = [0x00];
for (var i = 0; i < content.length; i++) {
data.push(content[i]);
resolve(buffer);
}
}));
const performExchange = () => {
let offsetSent = 0;
let firstReceived = true;
let toReceive = 0;
let received = Buffer.alloc(0);
const sendPart = () => {
if (offsetSent === transport.length) {
return receivePart();
}
_this2.device.write(data);
return Promise.resolve(content.length);
};
var recv = function recv() {
return new Promise(function (resolve, reject) {
return _this2.device.read(function (err, res) {
if (err || !res) reject(err);else {
var buffer = Buffer.from(res);
if (_this2.debug) {
console.log("<=" + buffer.toString("hex"));
}
resolve(buffer);
}
});
const blockSize = transport.length - offsetSent > 64 ? 64 : transport.length - offsetSent;
let block = transport.slice(offsetSent, offsetSent + blockSize);
const paddingSize = 64 - block.length;
if (paddingSize !== 0) {
let padding = Buffer.alloc(paddingSize).fill(0);
block = Buffer.concat([block, padding], block.length + paddingSize);
}
return send(block).then(() => {
offsetSent += blockSize;
return sendPart();
});
};
var performExchange = function performExchange() {
var offsetSent = 0;
var firstReceived = true;
var toReceive = 0;
var received = Buffer.alloc(0);
var sendPart = function sendPart() {
if (offsetSent === transport.length) {
return receivePart();
}
var blockSize = transport.length - offsetSent > 64 ? 64 : transport.length - offsetSent;
var block = transport.slice(offsetSent, offsetSent + blockSize);
var paddingSize = 64 - block.length;
if (paddingSize !== 0) {
var padding = Buffer.alloc(paddingSize).fill(0);
block = Buffer.concat([block, padding], block.length + paddingSize);
}
return send(block).then(function () {
offsetSent += blockSize;
return sendPart();
});
};
var receivePart = function receivePart() {
if (!_this2.ledgerTransport) {
return recv().then(function (result) {
received = Buffer.concat([received, result], received.length + result.length);
if (firstReceived) {
firstReceived = false;
if (received.length === 2 || received[0] !== 0x61) {
return received;
} else {
toReceive = received[1];
if (toReceive === 0) {
toReceive = 256;
}
toReceive += 2;
}
}
if (toReceive < 64) {
const receivePart = () => {
if (!this.ledgerTransport) {
return recv().then(result => {
received = Buffer.concat([received, result], received.length + result.length);
if (firstReceived) {
firstReceived = false;
if (received.length === 2 || received[0] !== 0x61) {
return received;
} else {
toReceive -= 64;
return receivePart();
toReceive = received[1];
if (toReceive === 0) {
toReceive = 256;
}
toReceive += 2;
}
});
} else {
return recv().then(function (result) {
received = Buffer.concat([received, result], received.length + result.length);
var response = ledgerUnwrap(0x0101, received, 64);
if (typeof response !== "undefined") {
return response;
} else {
return receivePart();
}
});
}
};
return sendPart();
};
performExchange().then(function (result) {
var status = void 0,
response = void 0,
resultBin = result;
if (!_this2.ledgerTransport) {
if (resultBin.length === 2 || resultBin[0] !== 0x61) {
status = resultBin[0] << 8 | resultBin[1];
response = resultBin.toString("hex");
} else {
var size = resultBin[1];
// fake T0
if (size === 0) {
size = 256;
}
response = resultBin.toString("hex", 2);
status = resultBin[2 + size] << 8 | resultBin[2 + size + 1];
}
if (toReceive < 64) {
return received;
} else {
toReceive -= 64;
return receivePart();
}
});
} else {
response = resultBin.toString("hex");
status = resultBin[resultBin.length - 2] << 8 | resultBin[resultBin.length - 1];
return recv().then(result => {
received = Buffer.concat([received, result], received.length + result.length);
const response = ledgerUnwrap(0x0101, received, 64);
if (typeof response !== "undefined") {
return response;
} else {
return receivePart();
}
});
}
// Check the status
var statusFound = statusList.some(function (s) {
return s === status;
});
if (!statusFound) {
deferred.reject("Invalid status " + status.toString(16));
}
// build the response
if (_this2.timeout !== 0) {
clearTimeout(exchangeTimeout);
}
return response;
}).then(function (response) {
// consume current promise
_this2.exchangeStack.shift();
// schedule next exchange
if (_this2.exchangeStack.length > 0) {
processNextExchange();
}
return response;
}, function (err) {
if (_this2.timeout !== 0) {
clearTimeout(exchangeTimeout);
}
throw err;
})
// plug to deferred
.then(deferred.resolve, deferred.reject);
};
return sendPart();
};
// schedule next exchange
processNextExchange();
}
performExchange().then(result => {
let status,
response,
resultBin = result;
if (!this.ledgerTransport) {
if (resultBin.length === 2 || resultBin[0] !== 0x61) {
status = resultBin[0] << 8 | resultBin[1];
response = resultBin.toString("hex");
} else {
let size = resultBin[1];
// fake T0
if (size === 0) {
size = 256;
}
// the exchangeStack will process the promise when possible
return deferred.promise;
}
}, {
key: "setScrambleKey",
value: function setScrambleKey() {}
}, {
key: "close",
value: function close() {
this.device.close();
return Promise.resolve();
}
}], [{
key: "open",
value: function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(path) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", Promise.resolve(new TransportNodeHid(new _nodeHid2.default.HID(path))));
case 1:
case "end":
return _context.stop();
response = resultBin.toString("hex", 2);
status = resultBin[2 + size] << 8 | resultBin[2 + size + 1];
}
} else {
response = resultBin.toString("hex");
status = resultBin[resultBin.length - 2] << 8 | resultBin[resultBin.length - 1];
}
}, _callee, this);
}));
// Check the status
const statusFound = statusList.some(s => s === status);
if (!statusFound) {
deferred.reject("Invalid status " + status.toString(16));
}
// build the response
if (this.timeout !== 0) {
clearTimeout(exchangeTimeout);
}
return response;
}).then(response => {
// consume current promise
this.exchangeStack.shift();
function open(_x4) {
return _ref.apply(this, arguments);
}
// schedule next exchange
if (this.exchangeStack.length > 0) {
processNextExchange();
}
return response;
}, err => {
if (this.timeout !== 0) {
clearTimeout(exchangeTimeout);
}
throw err;
})
// plug to deferred
.then(deferred.resolve, deferred.reject);
};
return open;
}()
// schedule next exchange
processNextExchange();
}
/**
* static function to create a new Transport from the first connected Ledger device found in USB
*/
// the exchangeStack will process the promise when possible
return deferred.promise;
}
}, {
key: "create",
value: function create(timeout, debug) {
return TransportNodeHid.list().then(function (result) {
if (result.length === 0) {
throw "No device found";
}
return new TransportNodeHid(new _nodeHid2.default.HID(result[0]), true, timeout, debug);
});
}
}]);
setScrambleKey() {}
return TransportNodeHid;
}(_hwTransport2.default);
close() {
this.device.close();
return Promise.resolve();
}
}
exports.default = TransportNodeHid;
TransportNodeHid.list = function () {
return Promise.resolve((0, _getDevices2.default)().filter(function (device) {
return device.vendorId === 0x2581 && device.productId === 0x3b7c || device.vendorId === 0x2c97;
}).map(function (d) {
return d.path;
}));
};
TransportNodeHid.list = () => Promise.resolve((0, _getDevices2.default)().filter(device => device.vendorId === 0x2581 && device.productId === 0x3b7c || device.vendorId === 0x2c97).map(d => d.path));
TransportNodeHid.discover = function (observer) {
var unsubscribed = false;
TransportNodeHid.discover = observer => {
let unsubscribed = false;
function unsubscribe() {
unsubscribed = true;
}
undefined.list().then(function (paths) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = paths[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var path = _step.value;
if (!unsubscribed) {
observer.next(path);
}
undefined.list().then(paths => {
for (const path of paths) {
if (!unsubscribed) {
observer.next(path);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
});
// TODO needs to also discover new plugged connection...
return { unsubscribe: unsubscribe };
return { unsubscribe };
};
exports.default = TransportNodeHid;
//# sourceMappingURL=TransportNodeHid.js.map
{
"name": "@ledgerhq/hw-transport-node-hid",
"version": "1.1.1-beta.068e2a14",
"version": "1.1.2-beta.068e2a14",
"description": "Ledger Hardware Wallet Node implementation of the communication layer, using node-hid",

@@ -28,3 +28,3 @@ "keywords": [

"dependencies": {
"@ledgerhq/hw-transport": "^1.1.1-beta.068e2a14",
"@ledgerhq/hw-transport": "^1.1.2-beta.068e2a14",
"node-hid": "^0.7.2"

@@ -31,0 +31,0 @@ },

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc