4.2 KiB
commands/files/files
(no submodules)
Purpose
Local-packer file-transport commands: prepareFileCommand,
validateFileCommand, getFileStatsCommand, validatePacketCommand.
These four functions implement the operator-facing surface every file-
transport bin in @suaveplan/server-keys calls into. Reconstruction
lives in the sibling serve-file.ts. The implementation is fully local —
no HTTP, no remote file server — backed by @suaveplan/packer's
whole-file Packer / Unpacker and plain Node fs.
The choice of a local packer (rather than an HTTP client to a remote file-server, which the upstream package shipped) was made deliberately: the upstream HTTP design forces operators to stand up a separate file-server before they can prepare or serve a file, and the binary contract is dominated by the packet wire format anyway. Owning the format here keeps the suaveplan test surface auditable without a network hop and removes a non-trivial deployment dependency.
Features
- Fixed-size packetisation (
packetSize, default 1 MiB) with a JSON envelope per packet on disk. - ed25519 signature per packet using the vault's
signslot secret; recipient verifies against the manifest'ssignerPublicKey. - Manifest is a single JSON document that lists every packet's
index,checksum,filename, andoriginalSize. - Cooperative abort at every packet boundary via
options.signal. - Typed
ServerKeysErrorfor every failure (INVALID_INPUT,VAULT_DECRYPT_FAILED,PACKET_INTEGRITY_FAILED,FILE_NOT_FOUND,ABORTED).
Usage: Basic
import {
prepareFileCommand,
validateFileCommand,
getFileStatsCommand,
} from "@suaveplan/server-keys/commands/files/files";
const stats = await getFileStatsCommand("/tmp/data.bin", {
packetSize: 256 * 1024,
});
console.log(stats.estimatedPackets);
await prepareFileCommand(
"/tmp/data.bin",
"/tmp/keys/server.vault",
"serverpw1234",
{ output: "/tmp/prepared", packetSize: 256 * 1024 },
);
const result = await validateFileCommand("/tmp/prepared");
expect(result.isComplete).toBe(true);
expect(result.invalidPackets).toEqual([]);
Usage: Advanced
Single-packet validation against an explicit hex public key (useful for spot-checking a remote-supplied packet without trusting the colocated manifest):
import { validatePacketCommand } from "@suaveplan/server-keys/commands/files/files";
const r = await validatePacketCommand(
"/tmp/prepared/packet.000000.bin",
"abcd...ed25519-public-key-hex",
);
expect(r.isValid).toBe(true);
Detect a tampered packet:
import { promises as fs } from "node:fs";
const target = "/tmp/prepared/packet.000003.bin";
const original = await fs.readFile(target, "utf-8");
const obj = JSON.parse(original);
const bytes = Buffer.from(obj.data, "hex");
bytes[10] ^= 0xff;
obj.data = bytes.toString("hex");
await fs.writeFile(target, JSON.stringify(obj));
const r = await validateFileCommand("/tmp/prepared");
expect(r.isComplete).toBe(false);
expect(r.invalidPackets).toContain(3);
API Reference
prepareFileCommand(filePath, vaultPath, password, options?) => Promise<FileManifest>validateFileCommand(packetDir, options?) => Promise<ValidateFileResult>getFileStatsCommand(filePath, options?) => Promise<FileStatsResult>validatePacketCommand(packetPath, verifyKeyHex, options?) => Promise<ValidatePacketResult>
All take FileCommandOptions = { output?, packetSize?, logger?, signal? }.
Implementation Notes
prepareFileCommand constructs a new Packer per packet so the
underlying event bus stays scoped to a single pack call — the abstract
Packer is an EventEmitter and we don't want pack events leaking
across packets. Each packet stores its signature, data, checksum,
and originalSize in a small JSON envelope ({ data, signature, checksum, originalSize }), all hex-encoded — operators inspecting
packets by hand can paste them into a hex viewer without further
tooling. The intentional compressionLevel: 0 (no gzip) keeps each
packet's plaintext slice byte-identical to the input region; without
this, signing operates over the gzip stream and reconstruction
requires inverting it, which is an avoidable layer for the local
transport.