73 lines
2.1 KiB
JavaScript
73 lines
2.1 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
import { dirname, resolve } from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
const SIZE = 2 * 1024 * 1024;
|
|
const SHA1 = "f2f52230b536214ef7c9924f483392993e226cfb";
|
|
|
|
// Never print the private URL or network errors that might contain it.
|
|
export async function downloadPrivateRom(url, destination, fetchImpl = fetch) {
|
|
if (!url || !destination)
|
|
throw new Error("Set CRYSTAL_ROM_URL and CRYSTAL_ROM_PATH.");
|
|
let parsed;
|
|
try {
|
|
parsed = new URL(url);
|
|
} catch {
|
|
throw new Error("CRYSTAL_ROM_URL must be a direct HTTPS download URL.");
|
|
}
|
|
if (parsed.protocol !== "https:")
|
|
throw new Error("CRYSTAL_ROM_URL must use HTTPS.");
|
|
|
|
let response;
|
|
let bytes;
|
|
try {
|
|
response = await fetchImpl(parsed, {
|
|
redirect: "error",
|
|
signal: AbortSignal.timeout(60_000),
|
|
});
|
|
if (response.ok) {
|
|
const chunks = [];
|
|
let size = 0;
|
|
for await (const chunk of response.body) {
|
|
size += chunk.length;
|
|
if (size > SIZE) throw new Error("oversized");
|
|
chunks.push(chunk);
|
|
}
|
|
bytes = Buffer.concat(chunks);
|
|
}
|
|
} catch {
|
|
throw new Error(
|
|
"Private ROM download failed. Check access, HTTPS, direct URL, size and runner IP restrictions.",
|
|
);
|
|
}
|
|
if (!response.ok)
|
|
throw new Error(`Private ROM server returned HTTP ${response.status}.`);
|
|
if (
|
|
bytes.length !== SIZE ||
|
|
createHash("sha1").update(bytes).digest("hex") !== SHA1
|
|
)
|
|
throw new Error(
|
|
"Private ROM must match the 2 MiB Crystal 1.1 profile (SHA-1 verification failed).",
|
|
);
|
|
|
|
await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
|
|
await writeFile(destination, bytes, { mode: 0o600, flag: "wx" });
|
|
}
|
|
|
|
if (
|
|
process.argv[1] &&
|
|
import.meta.url === pathToFileURL(resolve(process.argv[1])).href
|
|
) {
|
|
try {
|
|
await downloadPrivateRom(
|
|
process.env.CRYSTAL_ROM_URL,
|
|
process.env.CRYSTAL_ROM_PATH,
|
|
);
|
|
console.log("Private Crystal 1.1 ROM downloaded and verified.");
|
|
} catch (error) {
|
|
console.error(error.message);
|
|
process.exitCode = 1;
|
|
}
|
|
}
|