Socket
Socket
Sign inDemoInstall

@ledgerhq/hw-transport-webhid

Package Overview
Dependencies
Maintainers
12
Versions
242
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ledgerhq/hw-transport-webhid - npm Package Compare versions

Comparing version 4.74.3-alpha.6 to 4.77.0

559

lib/TransportWebHID.js

@@ -6,48 +6,97 @@ "use strict";

});
exports.default = void 0;
var _hwTransport = _interopRequireDefault(require("@ledgerhq/hw-transport"));
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 _hidFraming = _interopRequireDefault(require("@ledgerhq/devices/lib/hid-framing"));
var requestLedgerDevice = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var device;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return getHID().requestDevice({ filters: ledgerDevices });
var _devices = require("@ledgerhq/devices");
case 2:
device = _context.sent;
return _context.abrupt("return", device);
var _logs = require("@ledgerhq/logs");
case 4:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
var _errors = require("@ledgerhq/errors");
return function requestLedgerDevice() {
return _ref.apply(this, arguments);
};
}();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var getLedgerDevices = function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
var devices;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return getHID().getDevices();
const ledgerDevices = [{
vendorId: _devices.ledgerUSBVendorId
}];
case 2:
devices = _context2.sent;
return _context2.abrupt("return", devices.filter(function (d) {
return d.vendorId === _devices.ledgerUSBVendorId;
}));
const isSupported = () => Promise.resolve(!!(global.navigator && global.navigator.hid));
case 4:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
const getHID = () => {
// $FlowFixMe
const {
hid
} = navigator;
if (!hid) throw new _errors.TransportError("navigator.hid is not supported", "HIDNotSupported");
return hid;
};
return function getLedgerDevices() {
return _ref2.apply(this, arguments);
};
}();
async function requestLedgerDevice() {
const device = await getHID().requestDevice({
filters: ledgerDevices
});
return device;
}
var getFirstLedgerDevice = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
var existingDevices;
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return getLedgerDevices();
async function getLedgerDevices() {
const devices = await getHID().getDevices();
return devices.filter(d => d.vendorId === _devices.ledgerUSBVendorId);
}
case 2:
existingDevices = _context3.sent;
async function getFirstLedgerDevice() {
const existingDevices = await getLedgerDevices();
if (existingDevices.length > 0) return existingDevices[0];
return requestLedgerDevice();
}
if (!(existingDevices.length > 0)) {
_context3.next = 5;
break;
}
return _context3.abrupt("return", existingDevices[0]);
case 5:
return _context3.abrupt("return", requestLedgerDevice());
case 6:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
return function getFirstLedgerDevice() {
return _ref3.apply(this, arguments);
};
}();
/**

@@ -62,168 +111,380 @@ * WebHID Transport implementation

class TransportWebHID extends _hwTransport.default {
constructor(device) {
super();
this.device = void 0;
this.deviceModel = void 0;
this.channel = Math.floor(Math.random() * 0xffff);
this.packetSize = 64;
this.inputs = [];
this.inputCallback = void 0;
var _hwTransport = require("@ledgerhq/hw-transport");
this.read = () => {
if (this.inputs.length) {
return Promise.resolve(this.inputs.shift());
}
var _hwTransport2 = _interopRequireDefault(_hwTransport);
return new Promise(success => {
this.inputCallback = success;
});
};
var _hidFraming = require("@ledgerhq/devices/lib/hid-framing");
this.onInputReport = e => {
const buffer = new Buffer(e.data.buffer);
var _hidFraming2 = _interopRequireDefault(_hidFraming);
if (this.inputCallback) {
this.inputCallback(buffer);
this.inputCallback = null;
} else {
this.inputs.push(buffer);
}
};
var _devices = require("@ledgerhq/devices");
this._disconnectEmitted = false;
var _logs = require("@ledgerhq/logs");
this._emitDisconnect = e => {
if (this._disconnectEmitted) return;
this._disconnectEmitted = true;
this.emit("disconnect", e);
};
var _errors = require("@ledgerhq/errors");
this.exchange = apdu => this.exchangeAtomicImpl(async () => {
const {
channel,
packetSize
} = this;
(0, _logs.log)("apdu", "=> " + apdu.toString("hex"));
const framing = (0, _hidFraming.default)(channel, packetSize); // Write...
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const blocks = framing.makeBlocks(apdu);
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
for (let i = 0; i < blocks.length; i++) {
(0, _logs.log)("hid-frame", "=> " + blocks[i].toString("hex"));
await this.device.sendReport(0, blocks[i]);
} // Read...
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; }
let result;
let acc;
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"); }); }; }
while (!(result = framing.getReducedResult(acc))) {
const buffer = await this.read();
(0, _logs.log)("hid-frame", "<= " + buffer.toString("hex"));
acc = framing.reduceResponse(acc, buffer);
}
var ledgerDevices = [{ vendorId: _devices.ledgerUSBVendorId }];
(0, _logs.log)("apdu", "<= " + result.toString("hex"));
return result;
}).catch(e => {
if (e && e.message && e.message.includes("write")) {
this._emitDisconnect(e);
var isSupported = function isSupported() {
return Promise.resolve(!!(global.navigator && global.navigator.hid));
};
throw new _errors.DisconnectedDeviceDuringOperation(e.message);
}
var getHID = function getHID() {
// $FlowFixMe
var _navigator = navigator,
hid = _navigator.hid;
throw e;
});
if (!hid) throw new _errors.TransportError("navigator.hid is not supported", "HIDNotSupported");
return hid;
};
this.device = device;
this.deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
device.addEventListener("inputreport", this.onInputReport);
var TransportWebHID = function (_Transport) {
_inherits(TransportWebHID, _Transport);
function TransportWebHID(device) {
_classCallCheck(this, TransportWebHID);
var _this = _possibleConstructorReturn(this, (TransportWebHID.__proto__ || Object.getPrototypeOf(TransportWebHID)).call(this));
_initialiseProps.call(_this);
_this.device = device;
_this.deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
device.addEventListener("inputreport", _this.onInputReport);
return _this;
}
/**
* Similar to create() except it will always display the device permission (even if some devices are already accepted).
* Check if WebUSB transport is supported.
*/
static async request() {
const device = await requestLedgerDevice();
return TransportWebHID.open(device);
}
/**
* Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
* List the WebUSB devices that was previously authorized by the user.
*/
static async openConnected() {
const devices = await getLedgerDevices();
if (devices.length === 0) return null;
return TransportWebHID.open(devices[0]);
}
/**
* Create a Ledger transport with a HIDDevice
* Actively listen to WebUSB devices and emit ONE device
* that was either accepted before, if not it will trigger the native permission UI.
*
* Important: it must be called in the context of a UI click!
*/
static async open(device) {
await device.open();
const transport = new TransportWebHID(device);
_createClass(TransportWebHID, [{
key: "close",
const onDisconnect = e => {
if (device === e.device) {
getHID().removeEventListener("disconnect", onDisconnect);
transport._emitDisconnect(new _errors.DisconnectedDevice());
/**
* Release the transport device
*/
value: function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
return regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return this.exchangeBusyPromise;
case 2:
this.device.removeEventListener("inputreport", this.onInputReport);
_context4.next = 5;
return this.device.close();
case 5:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
function close() {
return _ref4.apply(this, arguments);
}
};
getHID().addEventListener("disconnect", onDisconnect);
return transport;
}
return close;
}()
/**
* Release the transport device
*/
async close() {
await this.exchangeBusyPromise;
this.device.removeEventListener("inputreport", this.onInputReport);
await this.device.close();
}
/**
* Exchange with the device using APDU protocol.
* @param apdu
* @returns a promise of apdu response
*/
/**
* Exchange with the device using APDU protocol.
* @param apdu
* @returns a promise of apdu response
*/
}, {
key: "setScrambleKey",
value: function setScrambleKey() {}
}], [{
key: "request",
setScrambleKey() {}
}
/**
* Similar to create() except it will always display the device permission (even if some devices are already accepted).
*/
value: function () {
var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
var device;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return requestLedgerDevice();
exports.default = TransportWebHID;
case 2:
device = _context5.sent;
return _context5.abrupt("return", TransportWebHID.open(device));
case 4:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
function request() {
return _ref5.apply(this, arguments);
}
return request;
}()
/**
* Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
*/
}, {
key: "openConnected",
value: function () {
var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {
var devices;
return regeneratorRuntime.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_context6.next = 2;
return getLedgerDevices();
case 2:
devices = _context6.sent;
if (!(devices.length === 0)) {
_context6.next = 5;
break;
}
return _context6.abrupt("return", null);
case 5:
return _context6.abrupt("return", TransportWebHID.open(devices[0]));
case 6:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
function openConnected() {
return _ref6.apply(this, arguments);
}
return openConnected;
}()
/**
* Create a Ledger transport with a HIDDevice
*/
}, {
key: "open",
value: function () {
var _ref7 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7(device) {
var transport, onDisconnect;
return regeneratorRuntime.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
_context7.next = 2;
return device.open();
case 2:
transport = new TransportWebHID(device);
onDisconnect = function onDisconnect(e) {
if (device === e.device) {
getHID().removeEventListener("disconnect", onDisconnect);
transport._emitDisconnect(new _errors.DisconnectedDevice());
}
};
getHID().addEventListener("disconnect", onDisconnect);
return _context7.abrupt("return", transport);
case 6:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
function open(_x) {
return _ref7.apply(this, arguments);
}
return open;
}()
}]);
return TransportWebHID;
}(_hwTransport2.default);
TransportWebHID.isSupported = isSupported;
TransportWebHID.list = getLedgerDevices;
TransportWebHID.listen = observer => {
let unsubscribed = false;
getFirstLedgerDevice().then(device => {
TransportWebHID.listen = function (observer) {
var unsubscribed = false;
getFirstLedgerDevice().then(function (device) {
if (!unsubscribed) {
const deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
observer.next({
type: "add",
descriptor: device,
deviceModel
});
var deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
observer.next({ type: "add", descriptor: device, deviceModel: deviceModel });
observer.complete();
}
}, error => {
}, function (error) {
observer.error(new _errors.TransportOpenUserCancelled(error.message));
});
function unsubscribe() {
unsubscribed = true;
}
return { unsubscribe: unsubscribe };
};
return {
unsubscribe
var _initialiseProps = function _initialiseProps() {
var _this2 = this;
this.channel = Math.floor(Math.random() * 0xffff);
this.packetSize = 64;
this.inputs = [];
this.read = function () {
if (_this2.inputs.length) {
return Promise.resolve(_this2.inputs.shift());
}
return new Promise(function (success) {
_this2.inputCallback = success;
});
};
this.onInputReport = function (e) {
var buffer = new Buffer(e.data.buffer);
if (_this2.inputCallback) {
_this2.inputCallback(buffer);
_this2.inputCallback = null;
} else {
_this2.inputs.push(buffer);
}
};
this._disconnectEmitted = false;
this._emitDisconnect = function (e) {
if (_this2._disconnectEmitted) return;
_this2._disconnectEmitted = true;
_this2.emit("disconnect", e);
};
this.exchange = function (apdu) {
return _this2.exchangeAtomicImpl(_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8() {
var channel, packetSize, framing, blocks, i, result, acc, buffer;
return regeneratorRuntime.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
channel = _this2.channel, packetSize = _this2.packetSize;
(0, _logs.log)("apdu", "=> " + apdu.toString("hex"));
framing = (0, _hidFraming2.default)(channel, packetSize);
// Write...
blocks = framing.makeBlocks(apdu);
i = 0;
case 5:
if (!(i < blocks.length)) {
_context8.next = 12;
break;
}
(0, _logs.log)("hid-frame", "=> " + blocks[i].toString("hex"));
_context8.next = 9;
return _this2.device.sendReport(0, blocks[i]);
case 9:
i++;
_context8.next = 5;
break;
case 12:
// Read...
result = void 0;
acc = void 0;
case 14:
if (result = framing.getReducedResult(acc)) {
_context8.next = 22;
break;
}
_context8.next = 17;
return _this2.read();
case 17:
buffer = _context8.sent;
(0, _logs.log)("hid-frame", "<= " + buffer.toString("hex"));
acc = framing.reduceResponse(acc, buffer);
_context8.next = 14;
break;
case 22:
(0, _logs.log)("apdu", "<= " + result.toString("hex"));
return _context8.abrupt("return", result);
case 24:
case "end":
return _context8.stop();
}
}
}, _callee8, _this2);
}))).catch(function (e) {
if (e && e.message && e.message.includes("write")) {
_this2._emitDisconnect(e);
throw new _errors.DisconnectedDeviceDuringOperation(e.message);
}
throw e;
});
};
};
exports.default = TransportWebHID;
//# sourceMappingURL=TransportWebHID.js.map
{
"name": "@ledgerhq/hw-transport-webhid",
"version": "4.74.3-alpha.6+0750e69",
"version": "4.77.0",
"description": "Ledger Hardware Wallet WebHID implementation of the communication layer",

@@ -27,6 +27,6 @@ "keywords": [

"dependencies": {
"@ledgerhq/devices": "^4.74.3-alpha.6+0750e69",
"@ledgerhq/errors": "^4.74.3-alpha.6+0750e69",
"@ledgerhq/hw-transport": "^4.74.3-alpha.6+0750e69",
"@ledgerhq/logs": "^4.74.3-alpha.6+0750e69"
"@ledgerhq/devices": "^4.77.0",
"@ledgerhq/errors": "^4.77.0",
"@ledgerhq/hw-transport": "^4.77.0",
"@ledgerhq/logs": "^4.72.0"
},

@@ -43,3 +43,3 @@ "devDependencies": {

},
"gitHead": "0750e6985bbd4a0faec44c9014352a46b094c66e"
"gitHead": "b25792920f55ec855fd74778ce37240ef7dbde01"
}

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