UNPKG

@ledgerhq/react-native-hid

Version:

Ledger Hardware Wallet Web implementation of the communication layer, using U2F api

136 lines 4.88 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_native_1 = require("react-native"); const devices_1 = require("@ledgerhq/devices"); const errors_1 = require("@ledgerhq/errors"); const logs_1 = require("@ledgerhq/logs"); const hw_transport_1 = __importDefault(require("@ledgerhq/hw-transport")); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const disconnectedErrors = [ "I/O error", "Attempt to invoke virtual method 'int android.hardware.usb.UsbDevice.getDeviceClass()' on a null object reference", "Invalid channel", "Permission denied by user for device", ]; const listLedgerDevices = async () => { const devices = await react_native_1.NativeModules.HID.getDeviceList(); return devices.filter(d => d.vendorId === devices_1.ledgerUSBVendorId); }; const liveDeviceEventsSubject = new rxjs_1.Subject(); react_native_1.DeviceEventEmitter.addListener("onDeviceConnect", (device) => { if (device.vendorId !== devices_1.ledgerUSBVendorId) return; const deviceModel = (0, devices_1.identifyUSBProductId)(device.productId); liveDeviceEventsSubject.next({ type: "add", descriptor: device, deviceModel, }); }); react_native_1.DeviceEventEmitter.addListener("onDeviceDisconnect", (device) => { if (device.vendorId !== devices_1.ledgerUSBVendorId) return; const deviceModel = (0, devices_1.identifyUSBProductId)(device.productId); liveDeviceEventsSubject.next({ type: "remove", descriptor: device, deviceModel, }); }); const liveDeviceEvents = liveDeviceEventsSubject; /** * Ledger's React Native HID Transport implementation * @example * import TransportHID from "@ledgerhq/react-native-hid"; * ... * TransportHID.create().then(transport => ...) */ class HIDTransport extends hw_transport_1.default { id; deviceModel; constructor(nativeId, productId) { super(); this.id = nativeId; this.deviceModel = (0, devices_1.identifyUSBProductId)(productId); } /** * Check if the transport is supported (basically true on Android) */ static isSupported = () => Promise.resolve(!!react_native_1.NativeModules.HID); /** * List currently connected devices. * @returns Promise of devices */ static async list() { if (!react_native_1.NativeModules.HID) return Promise.resolve([]); return await listLedgerDevices(); } /** * Listen to ledger devices events */ static listen(observer) { if (!react_native_1.NativeModules.HID) return { unsubscribe: () => { }, }; return (0, rxjs_1.concat)((0, rxjs_1.from)(listLedgerDevices()).pipe((0, operators_1.mergeMap)(devices => (0, rxjs_1.from)(devices.map(device => ({ type: "add", descriptor: device, deviceModel: (0, devices_1.identifyUSBProductId)(device.productId), }))))), liveDeviceEvents).subscribe(observer); } /** * Open a the transport with a Ledger device */ static async open(deviceObj) { try { const nativeObj = await react_native_1.NativeModules.HID.openDevice(deviceObj); return new HIDTransport(nativeObj.id, deviceObj.productId); } catch (error) { if (disconnectedErrors.includes(error.message)) { throw new errors_1.DisconnectedDevice(error.message); } throw error; } } /** * @param {*} apdu input value * @returns Promise of apdu response */ async exchange(apdu) { return this.exchangeAtomicImpl(async () => { try { const apduHex = apdu.toString("hex"); (0, logs_1.log)("apdu", "=> " + apduHex); const resultHex = await react_native_1.NativeModules.HID.exchange(this.id, apduHex); const res = Buffer.from(resultHex, "hex"); (0, logs_1.log)("apdu", "<= " + resultHex); return res; } catch (error) { if (disconnectedErrors.includes(error.message)) { this.emit("disconnect", error); throw new errors_1.DisconnectedDeviceDuringOperation(error.message); } throw error; } }); } /** * Close the transport * @returns Promise */ async close() { await this.exchangeBusyPromise; return react_native_1.NativeModules.HID.closeDevice(this.id); } setScrambleKey() { } } exports.default = HIDTransport; //# sourceMappingURL=index.js.map