Files
reverse-engineering-anything/src/browser/history/NodeCaptureProcess.ts
T

76 lines
2.7 KiB
TypeScript

import { readFile, writeFile } from "node:fs/promises";
import { z } from "zod";
import { readStableArtifact } from "../../artifacts/readStableArtifact.js";
import { webNetworkCaptureBudgetsSchema } from "../../domain/webNetworkCapture.js";
import { captureBudgets, withCaptureBudgets } from "./CaptureBudgets.js";
import { CaptureFormatError } from "./CaptureFormatError.js";
const requestSchema = z.strictObject({
snapshot_path: z.string(),
reply_path: z.string(),
sensitive_values: z.array(z.string().min(1)),
budgets: webNetworkCaptureBudgetsSchema,
});
/** Parse untrusted captures in an owned heap and return one complete bounded reply. */
const main = async (): Promise<void> => {
const format = z.enum(["har", "saz", "qlog"]).parse(process.argv[3]);
const request = requestSchema.parse(
JSON.parse(await readFile(process.argv[2] ?? "", "utf8")),
);
await withCaptureBudgets(request.budgets, async () => {
let reply: unknown;
try {
let value;
if (format !== "saz") {
const { decodeCaptureText } = await import("./CaptureJson.js");
const decoder =
format === "har"
? (await import("./HarCapture.js")).decodeHarCapture
: (await import("./QlogCapture.js")).decodeQlogCapture;
const snapshot = await readStableArtifact(
request.snapshot_path,
captureBudgets().inputBytes,
);
value = decoder(
decodeCaptureText(snapshot.bytes, format === "har" ? "HAR" : "qlog"),
request.sensitive_values,
);
} else {
const { decodeSazCapture } = await import("./SazCapture.js");
value = await decodeSazCapture(
request.snapshot_path,
request.sensitive_values,
);
}
reply = { ok: true, value };
} catch (cause: unknown) {
reply =
cause instanceof CaptureFormatError
? {
ok: false,
reason: cause.replyReason,
message: cause.message,
pointer: cause.pointer,
}
: {
ok: false,
reason: "decoder",
message: `Capture decoder failed unexpectedly (${cause instanceof Error ? cause.name : "unknown exception"}).`,
pointer: "",
};
}
let text = JSON.stringify(reply);
if (Buffer.byteLength(text) > captureBudgets().outputBytes)
text = JSON.stringify({
ok: false,
reason: "limit",
message:
"Capture reply exceeds max_reply_bytes; raise that per-call allowance and retry after cleanup.",
pointer: "",
});
await writeFile(request.reply_path, text, { flag: "wx", mode: 0o600 });
});
};
await main();