UNPKG

xud

Version:
157 lines 7.54 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()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const assert_1 = __importDefault(require("assert")); const crypto_1 = require("crypto"); const enums_1 = require("../constants/enums"); const cryptoUtils_1 = require("../utils/cryptoUtils"); const errors_1 = __importDefault(require("./errors")); /** Wire protocol msg framer */ let Framer = /** @class */ (() => { class Framer { constructor(network) { this.network = network; /** * Frame a packet with a header to be used as a wire msg */ this.frame = (packet, encryptionKey) => __awaiter(this, void 0, void 0, function* () { const packetRaw = packet.toRaw(); if (encryptionKey) { const msg = Buffer.allocUnsafe(Framer.ENCRYPTED_MSG_PAYLOAD_HEADER_LENGTH + packetRaw.length); // length msg.writeUInt32LE(packetRaw.length, 0); // type msg.writeUInt32LE(packet.type, 4); // packet packetRaw.copy(msg, 8); const ciphertext = yield this.encrypt(msg, encryptionKey); const encryptedMsg = Buffer.allocUnsafe(Framer.ENCRYPTED_MSG_HEADER_LENGTH + ciphertext.length); // length encryptedMsg.writeUInt32LE(ciphertext.length, 0); // ciphertext ciphertext.copy(encryptedMsg, 4); return encryptedMsg; } else { const msg = Buffer.allocUnsafe(Framer.MSG_HEADER_LENGTH + packetRaw.length); // network magic value msg.writeUInt32LE(this.network.magic, 0); // length msg.writeUInt32LE(packetRaw.length, 4); // type msg.writeUInt32LE(packet.type, 8); // checksum msg.writeUInt32LE(packet.checksum(), 12); // payload packetRaw.copy(msg, 16); return msg; } }); /** * Unframe a wire msg or an encrypted wire msg */ this.unframe = (msg, encryptionKey) => { let wireMsg; if (encryptionKey) { const length = msg.readUInt32LE(0); const ciphertext = msg.slice(Framer.ENCRYPTED_MSG_HEADER_LENGTH); if (length !== ciphertext.length) { throw errors_1.default.FRAMER_INVALID_MSG_LENGTH(length, ciphertext.length); } const decryptedMsg = this.decrypt(ciphertext, encryptionKey); wireMsg = { header: this.parseHeader(decryptedMsg, true), packet: decryptedMsg.slice(Framer.ENCRYPTED_MSG_PAYLOAD_HEADER_LENGTH), }; } else { wireMsg = { header: this.parseHeader(msg, false), packet: msg.slice(Framer.MSG_HEADER_LENGTH), }; } if (wireMsg.header.length !== wireMsg.packet.length) { throw errors_1.default.FRAMER_INVALID_MSG_LENGTH(wireMsg.header.length, wireMsg.packet.length); } return wireMsg; }; /** * Parse the length of a wire msg or an encrypted wire msg */ this.parseLength = (data, encrypted) => { const value = data.readUInt32LE(0); if (encrypted) { if (value === this.network.magic) { throw errors_1.default.FRAMER_MSG_NOT_ENCRYPTED; } return value; } if (value !== this.network.magic) { const network = enums_1.magicValsXuNetwork[value]; if (network) { throw errors_1.default.FRAMER_INCOMPATIBLE_MSG_ORIGIN_NETWORK(this.network.xuNetwork, network); } else { throw errors_1.default.FRAMER_INVALID_NETWORK_MAGIC_VALUE; } } return data.readUInt32LE(4); }; /** * Parse the header of a wire msg or an encrypted wire msg payload */ this.parseHeader = (msg, encrypted) => { if (encrypted) { assert_1.default(msg.length >= Framer.ENCRYPTED_MSG_PAYLOAD_HEADER_LENGTH, 'invalid msg header length: data is missing'); // length const length = msg.readUInt32LE(0); // type const type = msg.readUInt32LE(4); return { length, type }; } else { assert_1.default(msg.length >= Framer.MSG_HEADER_LENGTH, 'invalid msg header length: data is missing'); // network magic value const magic = msg.readUInt32LE(0); // length const length = msg.readUInt32LE(4); // type const type = msg.readUInt32LE(8); // checksum const checksum = msg.readUInt32LE(12); return { magic, type, length, checksum }; } }; this.encrypt = (plaintext, key) => __awaiter(this, void 0, void 0, function* () { const iv = yield cryptoUtils_1.randomBytes(Framer.ENCRYPTION_IV_LENGTH); const cipher = crypto_1.createCipheriv('aes-256-cbc', key, iv); return Buffer.concat([iv, cipher.update(plaintext), cipher.final()]); }); this.decrypt = (ciphertext, key) => { const iv = ciphertext.slice(0, Framer.ENCRYPTION_IV_LENGTH); const encrypted = ciphertext.slice(Framer.ENCRYPTION_IV_LENGTH); const decipher = crypto_1.createDecipheriv('aes-256-cbc', key, iv); return Buffer.concat([decipher.update(encrypted), decipher.final()]); }; } } Framer.MSG_HEADER_LENGTH = 16; Framer.ENCRYPTED_MSG_HEADER_LENGTH = 4; Framer.ENCRYPTED_MSG_PAYLOAD_HEADER_LENGTH = 8; Framer.ENCRYPTION_KEY_LENGTH = 32; Framer.ENCRYPTION_IV_LENGTH = 16; return Framer; })(); exports.default = Framer; //# sourceMappingURL=Framer.js.map