import * as ZLIB from 'node:zlib'; import * as CRYPTO from 'node:crypto'; import { type Writable } from 'node:stream'; /** One file about to become an archive member. */ export interface Member { /** The member's name inside the archive; a `/`-separated relative path. */ name: string; data: Buffer; mode?: number | undefined; /** When it was last modified: its file's time, or the time a source archive gave it. */ modified?: Date | undefined; } /** What a signer hands back once the finished hash exists. */ export interface Signature { signature: Buffer | Uint8Array; /** * Unsigned attributes to record beside the signature in the EOCD comment — * anything obtained *after* signing, which therefore cannot be inside what * the signature covers. */ fields?: Record | undefined; } /** * The two-phase signing interface. `chain` is known up front (it goes into * `AUTHORITY.PEM`, inside the hashed region); `sign()` is called afterwards * with the hash of the finished bytes. */ export interface Signer { kind?: string | undefined; /** Full PEM certificate chain, leaf first. */ chain: string; /** Digest the signature over the whole-file hash uses. */ signAlg: string; sign(digest: Buffer): Promise; } /** What `emit()` reports once the file has been fully written. */ export interface EmitResult { /** The whole-file hash, hex: recorded in the archive, signed or not. */ hash: string | null; signed: boolean; } export interface BundleOptions { /** Base directory the file list is relative to. */ base: string; /** Member names, relative to `base`. */ files: string[]; /** A launcher or binary to prepend, making the result self-running. */ prefix?: string | undefined; /** Digest for the whole-file hash and member digests (default: 'sha256'). */ hashAlg?: string | undefined; /** Digest the signature uses (default: 'sha256'). */ signAlg?: string | undefined; /** Shorthand for `signer: keySigner({ key, chain, signAlg })`. */ key?: Buffer | string | CRYPTO.KeyObject | undefined; chain?: string | undefined; signer?: Signer | undefined; /** One time for every member, instead of each file's own (see `parseDate()`). */ date?: Temporal.Instant | undefined; out: Writable; } export interface RebundleOptions { /** Path to the archive whose members are re-emitted, behind its own prefix. */ source: string; hashAlg?: string | undefined; signAlg?: string | undefined; key?: Buffer | string | CRYPTO.KeyObject | undefined; chain?: string | undefined; signer?: Signer | undefined; out: Writable; } export declare function fromDirectory(base: string, files: string[], date?: Temporal.Instant | undefined): AsyncGenerator; /** * A time for every member of an archive, from an ISO 8601 string and nothing * else: a date and time with its offset (`2024-05-01T12:00:00Z`, * `2024-05-01T14:00:00+02:00`), or a date alone (`2024-05-01`, midnight UTC). * A time without an offset is refused — it would be another moment in every * other timezone — and so are RFC 9557's `[…]` annotations, which ISO 8601 * does not have. Read by Temporal, so a day that does not exist is refused * rather than rolled over into the next month. */ export declare function parseDate(text: string): Temporal.Instant; export declare function fromArchive(zip: ZLIB.ZipFile): AsyncGenerator; /** * `SOURCE_DATE_EPOCH`, as reproducible builds define it: the time of the * source (say, its last commit, `git log -1 --format=%ct`), in seconds. No * member is later than it, so a fresh checkout — whose files all carry the * time of the checkout — still makes the same archive. Unset, nothing is * clamped. */ export declare function buildTime(): Date | undefined; /** * A Readable of the ZIP archive over `members`. Its members carry per-file * digests and its AUTHORITY.PEM manifest declares the algorithms and chain, but * the archive itself is left with an empty EOCD comment: the whole-file hash, * and any signature over it, are a property of the finished file and are * recorded by `emit()`. `baseOffset` seeds the archive's internal offsets for when it is * appended after a prefix. */ export declare function createArchive({ members, base, files, hashAlg, signAlg, chain, baseOffset }: { members?: AsyncIterable | Iterable | undefined; base?: string | undefined; files?: string[] | undefined; hashAlg?: string | undefined; signAlg?: string | undefined; chain?: string | undefined; baseOffset?: number | undefined; }): import("node:stream").Readable; /** * A signer backed by a private key and a certificate chain already on disk — * the offline-CA path, and the shape `sigstore.ts` implements too. */ export declare function keySigner({ key, chain, signAlg }: { key: Buffer | string | CRYPTO.KeyObject; chain: Buffer | string; signAlg?: string | undefined; }): Signer; /** Bytes to put before an archive: the first `length` bytes of the file at `path`. */ export interface Prefix { path: string; length: number; } /** * Build an archive from files on disk. `key`/`chain` are accepted as a * shorthand for `signer: keySigner({ key, chain, signAlg })`, so the * create-and-sign-in-one-step path stays available. */ export declare function bundle({ base, files, prefix, hashAlg, signAlg, key, chain, signer, date, out }: BundleOptions): Promise; /** * Re-emit an existing archive with a new signature: the same members, behind * the same prefix. This is what `bundle sign` runs. `source` is a path to an * archive, signed or not — its members are read out, its old AUTHORITY.PEM is * dropped for one carrying the signer's chain, and everything is laid down * again behind the bytes that preceded it before the result is hashed and * signed as a whole. Which prefix an archive has is decided when it is * created, where it can be reviewed, and never here. */ export declare function rebundle({ source, hashAlg, signAlg, key, chain, signer, out }: RebundleOptions): Promise; /** * Re-emit an existing archive's members behind a different prefix, unsigned: * what turns an application archive into an executable, the SEA base in * front. Like `bundle()`, it decides a shape, and so its result is what gets * reviewed and then signed. Any prefix the source had is left behind. */ export declare function reprefix({ source, prefix, hashAlg, out }: { source: string; prefix: string; hashAlg?: string | undefined; out: Writable; }): Promise; /** * The member names an archive holds, in order, excluding AUTHORITY.PEM — for * reporting what is about to be re-signed without reading every member's bytes. */ export declare function members(source: string): string[]; /** * How far back from the end of a file node's ZIP reader looks for the end of * an archive (`TAIL_LENGTH` in node's lib/internal/zip/constants.js): the * record, a maximal comment, the Zip64 locator and record, and some slack. */ export declare const READER_WINDOW: number; /** * How many zero bytes to put between `prefix` and the archive after it, so * that no archive end inside the prefix is within the reader's window of the * end of the file. * * A prefix can carry an archive of its own: a SEA's file system is a ZIP in * its blob, near the end of the executable. With a small archive appended, the * reader looking back from the end finds two plausible archive ends, and * refuses the file as ambiguous — rightly, since two readers could disagree on * which archive it is. Moving the prefix's archive end out of the window, * however small what follows, leaves exactly one. The zeros are part of the * prefix, inside the signed region; a prefix with no archive end near its own * end gets none. */ export declare function separation(prefix: Prefix): number; /** * How many bytes precede the archive in `source`: its prefix — a `#!` * launcher, a node binary — or 0 for a plain archive. Read from the archive's * own structure: the earliest local file header any central-directory record * points at, whether the offsets are absolute (as this package writes them) or * relative to the archive's start (as `cat prefix archive.zip` leaves them). */ export declare function prefixLength(source: string): number; //# sourceMappingURL=archive.d.ts.map