Socket
Socket
Sign inDemoInstall

@ledgerhq/hw-transport-webusb

Package Overview
Dependencies
Maintainers
12
Versions
288
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

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

Comparing version 4.74.3-alpha.6 to 4.77.0

478

lib/TransportWebUSB.js

@@ -6,8 +6,13 @@ "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 _hwTransport = require("@ledgerhq/hw-transport");
var _hwTransport2 = _interopRequireDefault(_hwTransport);
var _hidFraming = require("@ledgerhq/devices/lib/hid-framing");
var _hidFraming2 = _interopRequireDefault(_hidFraming);
var _devices = require("@ledgerhq/devices");

@@ -23,4 +28,13 @@

const configurationValue = 1;
const endpointNumber = 3;
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 _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; }
var configurationValue = 1;
var endpointNumber = 3;
/**

@@ -34,60 +48,18 @@ * WebUSB Transport implementation

class TransportWebUSB extends _hwTransport.default {
constructor(device, interfaceNumber) {
super();
this.device = void 0;
this.deviceModel = void 0;
this.channel = Math.floor(Math.random() * 0xffff);
this.packetSize = 64;
this.interfaceNumber = void 0;
this._disconnectEmitted = false;
var TransportWebUSB = function (_Transport) {
_inherits(TransportWebUSB, _Transport);
this._emitDisconnect = e => {
if (this._disconnectEmitted) return;
this._disconnectEmitted = true;
this.emit("disconnect", e);
};
function TransportWebUSB(device, interfaceNumber) {
_classCallCheck(this, TransportWebUSB);
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...
var _this = _possibleConstructorReturn(this, (TransportWebUSB.__proto__ || Object.getPrototypeOf(TransportWebUSB)).call(this));
const blocks = framing.makeBlocks(apdu);
_initialiseProps.call(_this);
for (let i = 0; i < blocks.length; i++) {
(0, _logs.log)("hid-frame", "=> " + blocks[i].toString("hex"));
await this.device.transferOut(endpointNumber, blocks[i]);
} // Read...
_this.device = device;
_this.interfaceNumber = interfaceNumber;
_this.deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
return _this;
}
let result;
let acc;
while (!(result = framing.getReducedResult(acc))) {
const r = await this.device.transferIn(endpointNumber, packetSize);
const buffer = Buffer.from(r.data.buffer);
(0, _logs.log)("hid-frame", "<= " + buffer.toString("hex"));
acc = framing.reduceResponse(acc, buffer);
}
(0, _logs.log)("apdu", "<= " + result.toString("hex"));
return result;
}).catch(e => {
if (e && e.message && e.message.includes("disconnected")) {
this._emitDisconnect(e);
throw new _errors.DisconnectedDeviceDuringOperation(e.message);
}
throw e;
});
this.device = device;
this.interfaceNumber = interfaceNumber;
this.deviceModel = (0, _devices.identifyUSBProductId)(device.productId);
}
/**

@@ -99,101 +71,256 @@ * Check if WebUSB transport is supported.

/**
* Similar to create() except it will always display the device permission (even if some devices are already accepted).
* List the WebUSB devices that was previously authorized by the user.
*/
static async request() {
const device = await (0, _webusb.requestLedgerDevice)();
return TransportWebUSB.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).
*/
static async openConnected() {
const devices = await (0, _webusb.getLedgerDevices)();
if (devices.length === 0) return null;
return TransportWebUSB.open(devices[0]);
}
/**
* Create a Ledger transport with a USBDevice
* 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();
_createClass(TransportWebUSB, [{
key: "close",
if (device.configuration === null) {
await device.selectConfiguration(configurationValue);
}
await device.reset();
const iface = device.configurations[0].interfaces.find(({
alternates
}) => alternates.some(a => a.interfaceClass === 255));
/**
* Release the transport device
*/
value: function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return this.exchangeBusyPromise;
if (!iface) {
throw new _errors.TransportInterfaceNotAvailable("No WebUSB interface found for your Ledger device. Please upgrade firmware or contact techsupport.");
}
case 2:
_context.next = 4;
return this.device.releaseInterface(this.interfaceNumber);
const interfaceNumber = iface.interfaceNumber;
case 4:
_context.next = 6;
return this.device.reset();
try {
await device.claimInterface(interfaceNumber);
} catch (e) {
await device.close();
throw new _errors.TransportInterfaceNotAvailable(e.message);
}
case 6:
_context.next = 8;
return this.device.close();
const transport = new TransportWebUSB(device, interfaceNumber);
case 8:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
const onDisconnect = e => {
if (device === e.device) {
// $FlowFixMe
navigator.usb.removeEventListener("disconnect", onDisconnect);
function close() {
return _ref.apply(this, arguments);
}
transport._emitDisconnect(new _errors.DisconnectedDevice());
return close;
}()
/**
* Exchange with the device using APDU protocol.
* @param apdu
* @returns a promise of apdu response
*/
}, {
key: "setScrambleKey",
value: function setScrambleKey() {}
}], [{
key: "request",
/**
* Similar to create() except it will always display the device permission (even if some devices are already accepted).
*/
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
var device;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return (0, _webusb.requestLedgerDevice)();
case 2:
device = _context2.sent;
return _context2.abrupt("return", TransportWebUSB.open(device));
case 4:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function request() {
return _ref2.apply(this, arguments);
}
}; // $FlowFixMe
return request;
}()
navigator.usb.addEventListener("disconnect", onDisconnect);
return transport;
}
/**
* Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
*/
/**
* Release the transport device
*/
async close() {
await this.exchangeBusyPromise;
await this.device.releaseInterface(this.interfaceNumber);
await this.device.reset();
await this.device.close();
}
/**
* Exchange with the device using APDU protocol.
* @param apdu
* @returns a promise of apdu response
*/
}, {
key: "openConnected",
value: function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
var devices;
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return (0, _webusb.getLedgerDevices)();
case 2:
devices = _context3.sent;
setScrambleKey() {}
if (!(devices.length === 0)) {
_context3.next = 5;
break;
}
}
return _context3.abrupt("return", null);
exports.default = TransportWebUSB;
case 5:
return _context3.abrupt("return", TransportWebUSB.open(devices[0]));
case 6:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
function openConnected() {
return _ref3.apply(this, arguments);
}
return openConnected;
}()
/**
* Create a Ledger transport with a USBDevice
*/
}, {
key: "open",
value: function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(device) {
var iface, interfaceNumber, transport, onDisconnect;
return regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return device.open();
case 2:
if (!(device.configuration === null)) {
_context4.next = 5;
break;
}
_context4.next = 5;
return device.selectConfiguration(configurationValue);
case 5:
_context4.next = 7;
return device.reset();
case 7:
iface = device.configurations[0].interfaces.find(function (_ref5) {
var alternates = _ref5.alternates;
return alternates.some(function (a) {
return a.interfaceClass === 255;
});
});
if (iface) {
_context4.next = 10;
break;
}
throw new _errors.TransportInterfaceNotAvailable("No WebUSB interface found for your Ledger device. Please upgrade firmware or contact techsupport.");
case 10:
interfaceNumber = iface.interfaceNumber;
_context4.prev = 11;
_context4.next = 14;
return device.claimInterface(interfaceNumber);
case 14:
_context4.next = 21;
break;
case 16:
_context4.prev = 16;
_context4.t0 = _context4["catch"](11);
_context4.next = 20;
return device.close();
case 20:
throw new _errors.TransportInterfaceNotAvailable(_context4.t0.message);
case 21:
transport = new TransportWebUSB(device, interfaceNumber);
onDisconnect = function onDisconnect(e) {
if (device === e.device) {
// $FlowFixMe
navigator.usb.removeEventListener("disconnect", onDisconnect);
transport._emitDisconnect(new _errors.DisconnectedDevice());
}
};
// $FlowFixMe
navigator.usb.addEventListener("disconnect", onDisconnect);
return _context4.abrupt("return", transport);
case 25:
case "end":
return _context4.stop();
}
}
}, _callee4, this, [[11, 16]]);
}));
function open(_x) {
return _ref4.apply(this, arguments);
}
return open;
}()
}]);
return TransportWebUSB;
}(_hwTransport2.default);
TransportWebUSB.isSupported = _webusb.isSupported;
TransportWebUSB.list = _webusb.getLedgerDevices;
TransportWebUSB.listen = observer => {
let unsubscribed = false;
(0, _webusb.getFirstLedgerDevice)().then(device => {
TransportWebUSB.listen = function (observer) {
var unsubscribed = false;
(0, _webusb.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) {
if (window.DOMException && error instanceof window.DOMException && error.code === 18) {

@@ -205,11 +332,100 @@ observer.error(new _errors.TransportWebUSBGestureRequired(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._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 _callee5() {
var channel, packetSize, framing, blocks, i, result, acc, r, buffer;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.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)) {
_context5.next = 12;
break;
}
(0, _logs.log)("hid-frame", "=> " + blocks[i].toString("hex"));
_context5.next = 9;
return _this2.device.transferOut(endpointNumber, blocks[i]);
case 9:
i++;
_context5.next = 5;
break;
case 12:
// Read...
result = void 0;
acc = void 0;
case 14:
if (result = framing.getReducedResult(acc)) {
_context5.next = 23;
break;
}
_context5.next = 17;
return _this2.device.transferIn(endpointNumber, packetSize);
case 17:
r = _context5.sent;
buffer = Buffer.from(r.data.buffer);
(0, _logs.log)("hid-frame", "<= " + buffer.toString("hex"));
acc = framing.reduceResponse(acc, buffer);
_context5.next = 14;
break;
case 23:
(0, _logs.log)("apdu", "<= " + result.toString("hex"));
return _context5.abrupt("return", result);
case 25:
case "end":
return _context5.stop();
}
}
}, _callee5, _this2);
}))).catch(function (e) {
if (e && e.message && e.message.includes("disconnected")) {
_this2._emitDisconnect(e);
throw new _errors.DisconnectedDeviceDuringOperation(e.message);
}
throw e;
});
};
};
exports.default = TransportWebUSB;
//# sourceMappingURL=TransportWebUSB.js.map

@@ -6,37 +6,107 @@ "use strict";

});
exports.requestLedgerDevice = requestLedgerDevice;
exports.getLedgerDevices = getLedgerDevices;
exports.getFirstLedgerDevice = getFirstLedgerDevice;
exports.isSupported = void 0;
exports.isSupported = exports.getFirstLedgerDevice = exports.getLedgerDevices = exports.requestLedgerDevice = undefined;
var _devices = require("@ledgerhq/devices");
var requestLedgerDevice = exports.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 navigator.usb.requestDevice({ filters: ledgerDevices });
const ledgerDevices = [{
vendorId: _devices.ledgerUSBVendorId
}];
case 2:
device = _context.sent;
return _context.abrupt("return", device);
async function requestLedgerDevice() {
// $FlowFixMe
const device = await navigator.usb.requestDevice({
filters: ledgerDevices
});
return device;
}
case 4:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
async function getLedgerDevices() {
// $FlowFixMe
const devices = await navigator.usb.getDevices();
return devices.filter(d => d.vendorId === _devices.ledgerUSBVendorId);
}
return function requestLedgerDevice() {
return _ref.apply(this, arguments);
};
}();
async function getFirstLedgerDevice() {
const existingDevices = await getLedgerDevices();
if (existingDevices.length > 0) return existingDevices[0];
return requestLedgerDevice();
}
var getLedgerDevices = exports.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 navigator.usb.getDevices();
const isSupported = () => Promise.resolve(!!navigator && // $FlowFixMe
!!navigator.usb && typeof navigator.usb.getDevices === "function");
case 2:
devices = _context2.sent;
return _context2.abrupt("return", devices.filter(function (d) {
return d.vendorId === _devices.ledgerUSBVendorId;
}));
exports.isSupported = isSupported;
case 4:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function getLedgerDevices() {
return _ref2.apply(this, arguments);
};
}();
var getFirstLedgerDevice = exports.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();
case 2:
existingDevices = _context3.sent;
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);
};
}();
var _devices = require("@ledgerhq/devices");
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"); }); }; }
var ledgerDevices = [{ vendorId: _devices.ledgerUSBVendorId }];
var isSupported = exports.isSupported = function isSupported() {
return Promise.resolve(!!navigator &&
// $FlowFixMe
!!navigator.usb && typeof navigator.usb.getDevices === "function");
};
//# sourceMappingURL=webusb.js.map
{
"name": "@ledgerhq/hw-transport-webusb",
"version": "4.74.3-alpha.6+0750e69",
"version": "4.77.0",
"description": "Ledger Hardware Wallet WebUSB 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

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