#!/usr/bin/env node /** * Reads scripts/onion-nodes.json and writes: * lib/onionRoutes.generated.ts * tor/cyberlux-nodes.conf * nginx/cyberlux-onion-servers.inc * 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; function dedicatedNginx(port, entry) { const h = JSON.stringify(entry); return ` # ${entry} @ ${port} server { listen 127.0.0.1:${port}; server_name _; include /etc/nginx/cyberlux-server-common.inc; proxy_hide_header X-Powered-By; client_max_body_size 25m; location /checkout { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node ${h}; } location /api/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node ${h}; } location /forum { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node ${h}; } location /exchange { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node ${h}; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node ${h}; proxy_read_timeout 86400; } } `; } function wikiNginx(port) { return ` # wiki @ ${port} server { listen 127.0.0.1:${port}; server_name _; include /etc/nginx/cyberlux-server-common.inc; proxy_hide_header X-Powered-By; client_max_body_size 25m; location /checkout { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node "wiki"; } location /api/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "wiki"; } location /forum { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "wiki"; } location /exchange { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "wiki"; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node "wiki"; proxy_read_timeout 86400; } } `; } function wNginx(port) { return ` # shadow nodes (/w/[slug]) @ ${port} server { listen 127.0.0.1:${port}; server_name _; include /etc/nginx/cyberlux-server-common.inc; proxy_hide_header X-Powered-By; client_max_body_size 25m; location /checkout { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node "w"; } location /api/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "w"; } location /forum { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "w"; } location /exchange { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header X-Cyberlux-Node "w"; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Cyberlux-Node "w"; proxy_read_timeout 86400; } } `; } function torBlock(dir, port) { return ` HiddenServiceDir /var/lib/tor/${dir} HiddenServicePort 80 127.0.0.1:${port} HiddenServiceEnableIntroDoSDefense 1 HiddenServiceEnableIntroDoSRatePerSec 25 HiddenServiceEnableIntroDoSBurstPerSec 200`; } 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 = ["hub", "wiki", "w", ...Object.keys(dedicated).sort()]; 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; `; // fix typo "generon" -> "generate" let nginxInc = "# CyberLux — generated onion vhosts (included from nginx.example.conf)\n"; 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); if (n.kind === "hub") continue; if (n.kind === "dedicated") nginxInc += dedicatedNginx(n.port, n.entry); else if (n.kind === "wiki") nginxInc += wikiNginx(n.port); else if (n.kind === "w") nginxInc += wNginx(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"); fs.writeFileSync(path.join(REPO, "nginx", "cyberlux-onion-servers.inc"), nginxInc.trim() + "\n"); console.log( `[generate-onion-config] ${nodes.length} onions, nginx loopback ${minP}–${maxP}, TS entries: ${uniqueEntries.length}`, );