#!/usr/bin/env node /** * Reads scripts/onion-nodes.json and writes: * lib/onionRoutes.generated.ts * tor/cyberlux-nodes.conf * scripts/generated/tor-dirs.txt * scripts/generated/onion-labels.tsv * scripts/generated/onion-port-range.txt */ "use strict"; const fs = require("fs"); const path = require("path"); const REPO = path.join(__dirname, ".."); const jsonPath = path.join(__dirname, "onion-nodes.json"); const data = JSON.parse(fs.readFileSync(jsonPath, "utf8")); const nodes = data.nodes; const TOR_INTRO_DOS_RATE_PER_SEC = 12; const TOR_INTRO_DOS_BURST_PER_SEC = 80; const KNOWN_APP_ENTRIES = [ "hub", "wiki", "w", "account", "arb-academy", "awards", "barter", "chatter", "checkout", "comparison", "conspiracies", "darknet-atlas", "dashboard", "directory", "drop-box", "drops", "easter-eggs", "exchange", "forum", "game", "hidden-wiki", "inner-circle", "links", "market", "messages", "mixer", "presswire", "raffle", "red-room", "reviews", "sanctuary", "search", "secret-layer", "security-analysis", "sign-in", "sign-up", "support", "syndicate", "testimonials", "trees", "trust", "vault", "vendors", "wallets", "webring", ]; function torBlock(dir, port) { return ` HiddenServiceDir /var/lib/tor/${dir} HiddenServicePort 80 127.0.0.1:${port} HiddenServiceEnableIntroDoSDefense 1 HiddenServiceEnableIntroDoSRatePerSec ${TOR_INTRO_DOS_RATE_PER_SEC} HiddenServiceEnableIntroDoSBurstPerSec ${TOR_INTRO_DOS_BURST_PER_SEC}`; } const ports = nodes.map((n) => n.port); const minP = Math.min(...ports); const maxP = Math.max(...ports); const dedicated = {}; for (const n of nodes) { if (n.kind === "dedicated") dedicated[n.entry] = n.path; } const uniqueEntries = Array.from(new Set([...KNOWN_APP_ENTRIES, ...Object.keys(dedicated)])).sort((a, b) => { if (a === "hub") return -1; if (b === "hub") return 1; return a.localeCompare(b); }); const drLines = Object.keys(dedicated) .sort() .map((k) => ` ${JSON.stringify(k)}: ${JSON.stringify(dedicated[k])},`) .join("\n"); const ts = `// AUTO-GENERATED by scripts/generate-onion-config.cjs — do not edit export const CYBERLUX_ENTRY_VALUES = [ ${uniqueEntries.map((e) => ` ${JSON.stringify(e)},`).join("\n")} ] as const; export type CyberluxEntry = (typeof CYBERLUX_ENTRY_VALUES)[number]; export const DEDICATED_ROOT = { ${drLines} } as const; `; let torConf = "# CyberLux — generated v3 onion services (include from torrc)\n#\n# Tor ≥ 0.4.7: DoS lines follow each HiddenServiceDir/Port pair.\n"; for (const n of nodes) { torConf += torBlock(n.torDir, n.port); } const genDir = path.join(REPO, "scripts", "generated"); fs.mkdirSync(genDir, { recursive: true }); const torDirs = nodes.map((n) => n.torDir); fs.writeFileSync(path.join(genDir, "tor-dirs.txt"), torDirs.join("\n") + "\n"); const labels = []; for (const n of nodes) { let desc = ""; if (n.kind === "hub") desc = "Hub — full storefront"; else if (n.kind === "wiki") desc = "Wiki — / → /hidden-wiki"; else if (n.kind === "w") desc = "Shadow nodes — / → /syndicate, /x → /w/x"; else desc = `${n.entry} — / → ${n.path}`; labels.push(`${n.torDir}\t${desc}`); } fs.writeFileSync(path.join(genDir, "onion-labels.tsv"), labels.join("\n") + "\n"); fs.writeFileSync(path.join(genDir, "onion-port-range.txt"), `${minP} ${maxP}\n`); fs.writeFileSync(path.join(REPO, "lib", "onionRoutes.generated.ts"), ts); fs.writeFileSync(path.join(REPO, "tor", "cyberlux-nodes.conf"), torConf.trim() + "\n"); const onionLabel = nodes.length === 1 ? "onion" : "onions"; const loopbackLabel = minP === maxP ? `${minP}` : `${minP}–${maxP}`; console.log( `[generate-onion-config] ${nodes.length} ${onionLabel}, nginx loopback ${loopbackLabel}, TS entries: ${uniqueEntries.length}`, );