Socket
Socket
Sign inDemoInstall

@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.0.6 to 1.0.7

542

lib/CommNodeHid.js

@@ -7,2 +7,4 @@ "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");

@@ -22,6 +24,29 @@

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; } /********************************************************************************
* Ledger Node JS API
* (c) 2016-2017 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
// FIXME drop
function defer() {
let resolve, reject;
let promise = new Promise(function (success, failure) {
var resolve = void 0,
reject = void 0;
var promise = new Promise(function (success, failure) {
resolve = success;

@@ -31,3 +56,3 @@ reject = failure;

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

@@ -42,65 +67,37 @@

*/
/********************************************************************************
* Ledger Node JS API
* (c) 2016-2017 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
var CommNodeHid = function (_Comm) {
_inherits(CommNodeHid, _Comm);
class CommNodeHid extends _hwTransport2.default {
function CommNodeHid(device, ledgerTransport) {
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var debug = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
constructor(device, ledgerTransport, timeout = 0, debug = false) {
super();
_classCallCheck(this, CommNodeHid);
var _this = _possibleConstructorReturn(this, (CommNodeHid.__proto__ || Object.getPrototypeOf(CommNodeHid)).call(this));
if (typeof device === "string") {
this.device = new _nodeHid2.default.HID(device);
_this.device = new _nodeHid2.default.HID(device);
} else {
this.device = device;
_this.device = device;
}
this.ledgerTransport = ledgerTransport;
this.timeout = timeout;
this.exchangeStack = [];
this.debug = debug;
_this.ledgerTransport = ledgerTransport;
_this.timeout = timeout;
_this.exchangeStack = [];
_this.debug = debug;
return _this;
}
/**
* static function to create a new Comm from the first connected Ledger device found in USB
*/
static create(timeout, debug) {
return CommNodeHid.list().then(result => {
if (result.length === 0) {
throw "No device found";
}
return new CommNodeHid(new _nodeHid2.default.HID(result[0]), true, timeout, debug);
});
}
_createClass(CommNodeHid, [{
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;
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);
var tmp = Buffer.alloc(7);
tmp.writeUInt16BE(channel, 0);

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

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);
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);
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) {
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) {
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) {
return;

@@ -163,196 +142,257 @@ }

}
if (data[offset++] !== sequenceIdx >> 8) {
if (data[offset++] !== 0x00) {
throw "Invalid sequence";
}
if (data[offset++] !== (sequenceIdx & 0xff)) {
if (data[offset++] !== 0x00) {
throw "Invalid sequence";
}
blockSize = responseLength - response.length > packetSize - 5 ? packetSize - 5 : responseLength - response.length;
if (blockSize > data.length - offset) {
responseLength = (data[offset++] & 0xff) << 8;
responseLength |= data[offset++] & 0xff;
if (data.length < 7 + responseLength) {
return;
}
response = Buffer.concat([response, data.slice(offset, offset + blockSize)], response.length + blockSize);
var 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;
}
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;
}
const apdu = Buffer.from(apduHex, "hex");
var apdu = Buffer.from(apduHex, "hex");
const deferred = defer();
let exchangeTimeout;
let transport;
if (!this.ledgerTransport) {
transport = apdu;
} else {
transport = ledgerWrap(0x0101, apdu, 64);
}
var deferred = defer();
var exchangeTimeout = void 0;
var transport = void 0;
if (!this.ledgerTransport) {
transport = apdu;
} else {
transport = ledgerWrap(0x0101, apdu, 64);
}
if (this.timeout !== 0) {
exchangeTimeout = setTimeout(() => {
// Node.js supports timeouts
deferred.reject("timeout");
}, this.timeout);
}
if (this.timeout !== 0) {
exchangeTimeout = setTimeout(function () {
// 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) {
const processNextExchange = () => {
// don't pop it now, to avoid multiple at once
const deferred = this.exchangeStack[0];
if (this.exchangeStack.length === 1) {
var processNextExchange = function processNextExchange() {
// don't pop it now, to avoid multiple at once
var deferred = _this2.exchangeStack[0];
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 send = function send(content) {
if (_this2.debug) {
console.log("=>" + content.toString("hex"));
}
resolve(buffer);
}
}));
var data = [0x00];
for (var i = 0; i < content.length; i++) {
data.push(content[i]);
}
_this2.device.write(data);
return Promise.resolve(content.length);
};
const performExchange = () => {
let offsetSent = 0;
let firstReceived = true;
let toReceive = 0;
let received = Buffer.alloc(0);
const sendPart = () => {
if (offsetSent === transport.length) {
return receivePart();
}
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 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 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) {
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) {
return received;
} else {
toReceive = received[1];
if (toReceive === 0) {
toReceive = 256;
}
toReceive += 2;
toReceive -= 64;
return receivePart();
}
});
} 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;
}
if (toReceive < 64) {
return received;
} else {
toReceive -= 64;
return receivePart();
}
});
response = resultBin.toString("hex", 2);
status = resultBin[2 + size] << 8 | resultBin[2 + size + 1];
}
} else {
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();
}
});
response = resultBin.toString("hex");
status = resultBin[resultBin.length - 2] << 8 | resultBin[resultBin.length - 1];
}
};
return sendPart();
// 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);
};
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;
}
// schedule next exchange
processNextExchange();
}
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];
}
// 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();
// 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: "create",
// 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);
};
// schedule next exchange
processNextExchange();
/**
* static function to create a new Comm from the first connected Ledger device found in USB
*/
value: function create(timeout, debug) {
return CommNodeHid.list().then(function (result) {
if (result.length === 0) {
throw "No device found";
}
return new CommNodeHid(new _nodeHid2.default.HID(result[0]), true, timeout, debug);
});
}
}]);
// the exchangeStack will process the promise when possible
return deferred.promise;
}
return CommNodeHid;
}(_hwTransport2.default);
setScrambleKey() {}
CommNodeHid.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;
}));
};
close() {
this.device.close();
return Promise.resolve();
}
}
exports.default = CommNodeHid;
CommNodeHid.list = () => Promise.resolve((0, _getDevices2.default)().filter(device => device.vendorId === 0x2581 && device.productId === 0x3b7c || device.vendorId === 0x2c97).map(d => d.path));
//# sourceMappingURL=CommNodeHid.js.map

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

const myEE = new _events2.default();
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();
myEE.setMaxListeners(0);
let timeoutDetection = null;
let isListenDevices = false;
var timeoutDetection = null;
var isListenDevices = false;
exports.default = {
start: (delay = 100) => {
start: function start() {
var delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
if (isListenDevices) {

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

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

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

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

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

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

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

{
"name": "@ledgerhq/hw-transport-node-hid",
"version": "1.0.6",
"version": "1.0.7",
"description": "Ledger Hardware Wallet Node implementation of the communication layer, using node-hid",

@@ -5,0 +5,0 @@ "keywords": [

@@ -13,3 +13,3 @@ // @flow

export default {
start: (delay:number = 100) => {
start: (delay: number = 100) => {
if (isListenDevices) {

@@ -25,4 +25,7 @@ return;

const getFlatDevices = () => [...new Set(devices().map(device => flatDevice(device)))];
const getDeviceByPath = ids => listDevices.find(device => flatDevice(device) === ids);
const getFlatDevices = () => [
...new Set(devices().map(device => flatDevice(device)))
];
const getDeviceByPath = ids =>
listDevices.find(device => flatDevice(device) === ids);

@@ -35,4 +38,8 @@ let lastDevices = getFlatDevices();

const addDevice = currentDevices.find(device => !lastDevices.includes(device));
const removeDevice = lastDevices.find(device => !currentDevices.includes(device));
const addDevice = currentDevices.find(
device => !lastDevices.includes(device)
);
const removeDevice = lastDevices.find(
device => !currentDevices.includes(device)
);

@@ -46,3 +53,5 @@ if (addDevice) {

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

@@ -65,3 +74,3 @@

},
events: myEE,
events: myEE
};

Sorry, the diff of this file is not supported yet

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