rea/src/browser/history/HarCaptureProcess.ts

65 lines
2.1 KiB
TypeScript

import { readFile, writeFile } from "node:fs/promises";
import { TextDecoder } from "node:util";
import { z } from "zod";
import { readStableArtifact } from "../../artifacts/readStableArtifact.js";
import { WEB_NETWORK_CAPTURE_LIMITS } from "../../domain/webNetworkCapture.js";
import { CaptureFormatError } from "./CaptureFormatError.js";
import { decodeHarCapture } from "./HarCapture.js";
const requestSchema = z.strictObject({
snapshot_path: z.string(),
reply_path: z.string(),
sensitive_values: z.array(z.string().min(1)),
});
/** Decode untrusted HAR in an owned, bounded heap rather than the long-lived MCP process. */
const main = async (): Promise<void> => {
const request = requestSchema.parse(
JSON.parse(await readFile(process.argv[2] ?? "", "utf8")),
);
let reply: unknown;
try {
const snapshot = await readStableArtifact(
request.snapshot_path,
WEB_NETWORK_CAPTURE_LIMITS.inputBytes,
);
let text: string;
try {
text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
snapshot.bytes,
);
} catch {
throw new CaptureFormatError("format", "HAR is not valid UTF-8 JSON.");
}
reply = {
ok: true,
value: decodeHarCapture(text, request.sensitive_values),
};
} catch (cause: unknown) {
reply =
cause instanceof CaptureFormatError
? {
ok: false,
reason: cause.reason,
message: cause.message,
pointer: cause.pointer,
}
: {
ok: false,
reason: "decoder",
message: `HAR decoder failed unexpectedly (${cause instanceof Error ? cause.name : "unknown exception"}).`,
pointer: "",
};
}
let text = JSON.stringify(reply);
if (Buffer.byteLength(text) > WEB_NETWORK_CAPTURE_LIMITS.outputBytes)
text = JSON.stringify({
ok: false,
reason: "limit",
message: "HAR reply exceeds the complete-evidence output budget.",
pointer: "",
});
await writeFile(request.reply_path, text, { flag: "wx", mode: 0o600 });
};
await main();