UNPKG

@cityofzion/neon-ledger

Version:

Neon Ledger integration for Node.js

128 lines 5.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAppName = getAppName; exports.getAppVersion = getAppVersion; exports.getDevicePaths = getDevicePaths; exports.getPublicKey = getPublicKey; exports.getSignature = getSignature; const neon_core_1 = require("@cityofzion/neon-core"); const ErrorCode_1 = require("./ErrorCode"); const utils_1 = require("./utils"); const DEFAULT_STATUSLIST = [ErrorCode_1.StatusWord.OK]; var Command; (function (Command) { Command[Command["GET_APP_NAME"] = 0] = "GET_APP_NAME"; Command[Command["GET_VERSION"] = 1] = "GET_VERSION"; Command[Command["SIGN_TX"] = 2] = "SIGN_TX"; Command[Command["GET_PUBLIC_KEY"] = 4] = "GET_PUBLIC_KEY"; })(Command || (Command = {})); /** * Helper to send data chunks to sign. * @param ledger - Ledger instance * @param msg - data up to 510 character * @param chunk - data sequence number. Start at 0, increase by 1 * @param finalChunk - set to true if this is the last chunk for the command */ async function sendDataToSign(ledger, msg, chunk, finalChunk = false) { return await ledger.send(0x80, Command.SIGN_TX, chunk, finalChunk ? 0x00 : 0x80, Buffer.from(msg, "hex"), DEFAULT_STATUSLIST); } /** * Requests the open application name from the Ledger. * @param ledger - Ledger instance * @returns the ledger application name. Expected "NEO3" */ async function getAppName(ledger) { try { const response = await ledger.send(0x80, Command.GET_APP_NAME, 0x00, 0x00, undefined, DEFAULT_STATUSLIST); const version = response.toString("ascii"); return version.substring(0, version.length - 2); // take of status word } catch (e) { if ((0, ErrorCode_1.looksLikeTransportStatusError)(e)) { throw (0, ErrorCode_1.evalTransportError)(e); } throw e; } } /** * Requests the application version from the Ledger. * @param ledger - Ledger instance * @returns the application version in Major.Minor.Patch format i.e. "0.1.0" */ async function getAppVersion(ledger) { try { const response = await ledger.send(0x80, Command.GET_VERSION, 0x00, 0x00, undefined, DEFAULT_STATUSLIST); const major = response.readUInt8(0); const minor = response.readUInt8(1); const patch = response.readUInt8(2); return major.toString() + "." + minor.toString() + "." + patch.toString(); } catch (e) { if ((0, ErrorCode_1.looksLikeTransportStatusError)(e)) { throw (0, ErrorCode_1.evalTransportError)(e); } throw e; } } /** * Returns the list of connected Ledger devices. Throw if Ledger is not supported by the computer. * @param ledgerLibrary - Ledger library */ async function getDevicePaths(ledgerLibrary) { const supported = await ledgerLibrary.isSupported(); if (!supported) { throw new Error(`Your computer does not support the ledger!`); } return await ledgerLibrary.list(); } /** * Requests the public key of a requested address from the Ledger. * @param ledger - Ledger instance * @param bip44String - BIP44 string (40 bytes) * @param showAddressOnDevice - whether to show the public key as NEO3 address * on the Ledger * @returns An unencoded public key (65 bytes) */ async function getPublicKey(ledger, bip44String, showAddressOnDevice = false) { try { const response = await ledger.send(0x80, Command.GET_PUBLIC_KEY, 0x00, showAddressOnDevice ? 0x01 : 0x0, Buffer.from(bip44String, "hex"), DEFAULT_STATUSLIST); return response.toString("hex").substring(0, 130); } catch (e) { if ((0, ErrorCode_1.looksLikeTransportStatusError)(e)) { throw (0, ErrorCode_1.evalTransportError)(e); } throw e; } } /** * Requests the device to sign a message using the NEO application. * @param ledger - Ledger instance * @param payload - message to sign as a hexstring. * @param bip44String - BIP44 string (40 bytes) * @param network - MainNet, TestNet or custom network number * @returns Signature as a hexstring (64 bytes) */ async function getSignature(ledger, payload, bip44String, network) { await sendDataToSign(ledger, bip44String, 0); await sendDataToSign(ledger, neon_core_1.u.num2hexstring(network, 4, true), 1); const chunks = payload.match(/.{1,510}/g) || []; try { for (let i = 0; i < chunks.length - 1; i++) { await sendDataToSign(ledger, chunks[i], 2 + i); } const response = await sendDataToSign(ledger, chunks[chunks.length - 1], 2 + chunks.length, true); // Expected signature + 2 status bytes to be returned here upon completion if (response.length <= 2) { throw new Error(`No more data but Ledger did not return signature!`); } return (0, utils_1.DerToHexSignature)(response.toString("hex")); } catch (e) { if ((0, ErrorCode_1.looksLikeTransportStatusError)(e)) { throw (0, ErrorCode_1.evalTransportError)(e); } throw e; } } //# sourceMappingURL=main.js.map