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; } }