UNPKG

age-encryption

Version:

<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://github.com/FiloSottile/age/blob/main/logo/logo_white.svg"> <source media="(prefers-color-scheme: light)" srcset="https://github.com/FiloSottile/a

112 lines (111 loc) 3.33 kB
import { randomBytes } from "@noble/hashes/utils"; export class LineReader { s; transcript = []; buf = new Uint8Array(0); constructor(stream) { this.s = stream.getReader(); } async readLine() { const line = []; while (true) { const i = this.buf.indexOf("\n".charCodeAt(0)); if (i >= 0) { line.push(this.buf.subarray(0, i)); this.transcript.push(this.buf.subarray(0, i + 1)); this.buf = this.buf.subarray(i + 1); return asciiString(flatten(line)); } if (this.buf.length > 0) { line.push(this.buf); this.transcript.push(this.buf); } const next = await this.s.read(); if (next.done) { this.buf = flatten(line); return null; } this.buf = next.value; } } close() { this.s.releaseLock(); return { rest: this.buf, transcript: flatten(this.transcript) }; } } function asciiString(bytes) { bytes.forEach((b) => { if (b < 32 || b > 126) { throw Error("invalid non-ASCII byte in header"); } }); return new TextDecoder().decode(bytes); } export function flatten(arr) { const len = arr.reduce(((sum, line) => sum + line.length), 0); const out = new Uint8Array(len); let n = 0; for (const a of arr) { out.set(a, n); n += a.length; } return out; } export function prepend(s, ...prefixes) { return s.pipeThrough(new TransformStream({ start(controller) { for (const p of prefixes) { controller.enqueue(p); } } })); } export function stream(a) { // https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/from_static return new ReadableStream({ start(controller) { controller.enqueue(a); controller.close(); } }); } export async function readAll(stream) { if (!(stream instanceof ReadableStream)) { throw new Error("readAll expects a ReadableStream<Uint8Array>"); } return new Uint8Array(await new Response(stream).arrayBuffer()); } export async function readAllString(stream) { if (!(stream instanceof ReadableStream)) { throw new Error("readAllString expects a ReadableStream<Uint8Array>"); } return await new Response(stream).text(); } export async function read(stream, n) { const reader = stream.getReader(); const chunks = []; let readBytes = 0; while (readBytes < n) { const { done, value } = await reader.read(); if (done) { throw Error("stream ended before reading " + n + " bytes"); } chunks.push(value); readBytes += value.length; } reader.releaseLock(); const buf = flatten(chunks); const data = buf.subarray(0, n); const rest = prepend(stream, buf.subarray(n)); return { data, rest }; } export function randomBytesStream(n, chunk) { return new ReadableStream({ start(controller) { for (let i = 0; i < n; i += chunk) { controller.enqueue(randomBytes(Math.min(chunk, n - i))); } controller.close(); } }); }