UNPKG

@hazae41/ledger

Version:

Private and supply-chain hardened Ledger controller for TypeScript

98 lines (95 loc) 3.27 kB
import { Opaque, Readable } from '@hazae41/binary'; import { Cursor } from '@hazae41/cursor'; class InvalidHidTagError extends Error { tag; #class = InvalidHidTagError; name = this.#class.name; constructor(tag) { super(`Invalid HID tag ${tag}`); this.tag = tag; } } class HidFrame { channel; fragment; index; #class = HidFrame; static tag = 0x05; constructor(channel, fragment, index) { this.channel = channel; this.fragment = fragment; this.index = index; } sizeOrThrow() { return 2 + 1 + 2 + this.fragment.sizeOrThrow(); } writeOrThrow(cursor) { cursor.writeUint16OrThrow(this.channel); cursor.writeUint8OrThrow(this.#class.tag); cursor.writeUint16OrThrow(this.index); this.fragment.writeOrThrow(cursor); } static readOrThrow(cursor) { const channel = cursor.readUint16OrThrow(); const tag = cursor.readUint8OrThrow(); if (tag !== this.tag) throw new InvalidHidTagError(tag); const index = cursor.readUint16OrThrow(); const bytes = cursor.readAndCopyOrThrow(cursor.remaining); const fragment = new Opaque(bytes); return new HidFrame(channel, fragment, index); } static *splitOrThrow(channel, bytes) { const chunks = new Cursor(bytes).splitOrThrow(59); let chunk = chunks.next(); for (let i = 0; !chunk.done; chunk = chunks.next(), i++) yield new HidFrame(channel, new Opaque(chunk.value), i); return chunk.value; } static async unsplitOrThrow(channel, generator) { const first = await generator.next(); if (first.done) return first.value; const frames = Readable.readFromBytesOrThrow(HidContainer, first.value.fragment.bytes); const bytes = new Uint8Array(frames.length); const cursor = new Cursor(bytes); cursor.writeOrThrow(frames.fragment.bytes.slice(0, cursor.remaining)); if (!cursor.remaining) return cursor.bytes; let frame = await generator.next(); for (; !frame.done; frame = await generator.next()) { cursor.writeOrThrow(frame.value.fragment.bytes.slice(0, cursor.remaining)); if (!cursor.remaining) return cursor.bytes; continue; } return frame.value; } } class HidContainer { length; fragment; constructor(length, fragment) { this.length = length; this.fragment = fragment; } static newOrThrow(fragment) { return new HidContainer(fragment.sizeOrThrow(), fragment); } sizeOrThrow() { return Math.ceil((2 + this.length) / 59) * 59; } writeOrThrow(cursor) { cursor.writeUint16OrThrow(this.length); this.fragment.writeOrThrow(cursor); cursor.fillOrThrow(0, cursor.remaining); } static readOrThrow(cursor) { const length = cursor.readUint16OrThrow(); const bytes = cursor.readAndCopyOrThrow(cursor.remaining); const fragment = new Opaque(bytes); return new HidContainer(length, fragment); } } export { HidContainer, HidFrame, InvalidHidTagError }; //# sourceMappingURL=index.mjs.map