UNPKG

@terra-money/ledger-terra-js

Version:
294 lines 11.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sign = exports.showAddressAndPubKey = exports.getAddressAndPubKey = exports.publicKey = exports.getDeviceInfo = exports.getAppInfo = exports.getVersion = exports.serializePath = void 0; const constants_1 = require("./constants"); function errorCodeToString(statusCode) { if (statusCode in constants_1.ERROR_DESCRIPTION) { return constants_1.ERROR_DESCRIPTION[statusCode]; } return `Unknown Status Code: ${statusCode}`; } function isDict(v) { return typeof v === "object" && v !== null && !(v instanceof Array) && !(v instanceof Date); } function processErrorResponse(response) { if (response) { if (isDict(response)) { if (Object.prototype.hasOwnProperty.call(response, "statusCode")) { return { return_code: response.statusCode, error_message: errorCodeToString(response.statusCode), }; } if (Object.prototype.hasOwnProperty.call(response, "return_code") && Object.prototype.hasOwnProperty.call(response, "error_message")) { return response; } } return { return_code: 0xffff, error_message: response.toString(), }; } return { return_code: 0xffff, error_message: response.toString(), }; } function serializePath(path) { if (!path || path.length !== 5) { throw new TypeError("Invalid path."); } const buf = Buffer.alloc(20); buf.writeUInt32LE(0x80000000 + path[0], 0); buf.writeUInt32LE(0x80000000 + path[1], 4); buf.writeUInt32LE(0x80000000 + path[2], 8); buf.writeUInt32LE(path[3], 12); buf.writeUInt32LE(path[4], 16); return buf; } exports.serializePath = serializePath; function getVersion(transport) { return transport .send(constants_1.CLA, constants_1.INS.GET_VERSION, 0, 0) .then((response) => { const errorCodeData = response.slice(-2); const return_code = errorCodeData[0] * 256 + errorCodeData[1]; let targetId = 0; if (response.length >= 9) { targetId = (response[5] << 24) + (response[6] << 16) + (response[7] << 8) + (response[8] << 0); } return { return_code: return_code, error_message: errorCodeToString(return_code), test_mode: response[0] !== 0, major: response[1], minor: response[2], patch: response[3], device_locked: response[4] === 1, target_id: targetId.toString(16), }; }) .catch(processErrorResponse); } exports.getVersion = getVersion; function getAppInfo(transport) { return transport .send(0xb0, 0x01, 0, 0) .then((response) => { const errorCodeData = response.slice(-2); let return_code = errorCodeData[0] * 256 + errorCodeData[1]; let error_message; let app_name = "err"; let app_version = "err"; let flag_len = 0; let flags_value = 0; if (response[0] !== 1) { error_message = "response format ID not recognized"; return_code = 0x9001; } else { error_message = "No errors"; const appNameLen = response[1]; app_name = response.slice(2, 2 + appNameLen).toString("ascii"); let idx = 2 + appNameLen; const appVersionLen = response[idx]; idx += 1; app_version = response.slice(idx, idx + appVersionLen).toString("ascii"); idx += appVersionLen; const appFlagsLen = response[idx]; idx += 1; flag_len = appFlagsLen; flags_value = response[idx]; } return { return_code, error_message, app_name, app_version, flag_len, flags_value, flag_recovery: (flags_value & 1) !== 0, flag_signed_mcu_code: (flags_value & 2) !== 0, flag_onboarded: (flags_value & 4) !== 0, flag_pin_validated: (flags_value & 128) !== 0, }; }) .catch(processErrorResponse); } exports.getAppInfo = getAppInfo; function getDeviceInfo(transport) { return __awaiter(this, void 0, void 0, function* () { return transport .send(0xe0, 0x01, 0, 0, Buffer.from([]), [constants_1.ERROR_CODE.NoError, 0x6e00]) .then((response) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; if (returnCode === 0x6e00) { return { return_code: returnCode, error_message: "This command is only available in the Dashboard", }; } const target_id = response.slice(0, 4).toString("hex"); let pos = 4; const secureElementVersionLen = response[pos]; pos += 1; const se_version = response.slice(pos, pos + secureElementVersionLen).toString(); pos += secureElementVersionLen; const flagsLen = response[pos]; pos += 1; const flag = response.slice(pos, pos + flagsLen).toString("hex"); pos += flagsLen; const mcuVersionLen = response[pos]; pos += 1; let tmp = response.slice(pos, pos + mcuVersionLen); if (tmp[mcuVersionLen - 1] === 0) { tmp = response.slice(pos, pos + mcuVersionLen - 1); } const mcu_version = tmp.toString(); return { return_code: returnCode, error_message: errorCodeToString(returnCode), target_id, se_version, flag, mcu_version, }; }) .catch(processErrorResponse); }); } exports.getDeviceInfo = getDeviceInfo; function publicKey(transport, data) { return transport .send(constants_1.CLA, constants_1.INS.GET_ADDR_SECP256K1, 0, 0, data, [constants_1.ERROR_CODE.NoError]) .then((response) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; const compressedPk = response ? Buffer.from(response.slice(0, 33)) : null; return { pk: "OBSOLETE PROPERTY", compressed_pk: compressedPk ? compressedPk.toJSON() : compressedPk, return_code: returnCode, error_message: errorCodeToString(returnCode), }; }) .catch(processErrorResponse); } exports.publicKey = publicKey; function getAddressAndPubKey(transport, data) { return transport .send(constants_1.CLA, constants_1.INS.GET_ADDR_SECP256K1, constants_1.P1_VALUES.ONLY_RETRIEVE, 0, data, [constants_1.ERROR_CODE.NoError]) .then((response) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; const compressedPk = Buffer.from(response.slice(0, 33)); const bech32Address = Buffer.from(response.slice(33, -2)).toString(); return { bech32_address: bech32Address, compressed_pk: compressedPk.toJSON(), return_code: returnCode, error_message: errorCodeToString(returnCode), }; }) .catch(processErrorResponse); } exports.getAddressAndPubKey = getAddressAndPubKey; function showAddressAndPubKey(transport, data) { return transport .send(constants_1.CLA, constants_1.INS.GET_ADDR_SECP256K1, constants_1.P1_VALUES.SHOW_ADDRESS_IN_DEVICE, 0, data, [constants_1.ERROR_CODE.NoError]) .then((response) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; const compressedPk = Buffer.from(response.slice(0, 33)); const bech32Address = Buffer.from(response.slice(33, -2)).toString(); return { bech32_address: bech32Address, compressed_pk: compressedPk.toJSON(), return_code: returnCode, error_message: errorCodeToString(returnCode), }; }) .catch(processErrorResponse); } exports.showAddressAndPubKey = showAddressAndPubKey; function signGetChunks(path, message) { const result = serializePath(path); const chunks = []; if (result instanceof Buffer) { chunks.push(result); const buffer = Buffer.from(message); for (let i = 0; i < buffer.length; i += constants_1.CHUNK_SIZE) { let end = i + constants_1.CHUNK_SIZE; if (i > buffer.length) { end = buffer.length; } chunks.push(buffer.slice(i, end)); } } return chunks; } function signSendChunk(transport, chunkIdx, chunkNum, chunk) { let payloadType = constants_1.PAYLOAD_TYPE.ADD; if (chunkIdx === 1) { payloadType = constants_1.PAYLOAD_TYPE.INIT; } if (chunkIdx === chunkNum) { payloadType = constants_1.PAYLOAD_TYPE.LAST; } return transport .send(constants_1.CLA, constants_1.INS.SIGN_SECP256K1, payloadType, 0, chunk, [constants_1.ERROR_CODE.NoError, 0x6984, 0x6a80]) .then((response) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; let errorMessage = errorCodeToString(returnCode); if (returnCode === 0x6a80 || returnCode === 0x6984) { errorMessage = `${errorMessage} : ${response.slice(0, response.length - 2).toString("ascii")}`; } let signature = Buffer.from([]); if (response.length > 2) { signature = response.slice(0, response.length - 2); } return { signature: signature.toJSON(), return_code: returnCode, error_message: errorMessage, }; }) .catch(processErrorResponse); } function sign(transport, path, message) { const chunks = signGetChunks(path, message); return signSendChunk(transport, 1, chunks.length, chunks[0]) .then((response) => __awaiter(this, void 0, void 0, function* () { let result = { return_code: response.return_code, error_message: response.error_message, signature: { type: "Buffer", data: [] }, }; for (let i = 1; i < chunks.length; i += 1) { result = yield signSendChunk(transport, 1 + i, chunks.length, chunks[i]); if (result.return_code !== constants_1.ERROR_CODE.NoError) { break; } } return { return_code: result.return_code, error_message: result.error_message, signature: result.signature, }; })) .catch(processErrorResponse); } exports.sign = sign; //# sourceMappingURL=device.js.map