const https = require("https"); const { UA } = require("../data/constants"); // MANRS Participants Cache (scraped from public HTML page, 24h TTL) let manrsAsnSet = null; // Set of member ASNs let manrsLastFetch = 0; let manrsFetching = false; const MANRS_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours async function ensureManrsCache() { const now = Date.now(); if (manrsAsnSet && (now - manrsLastFetch) < MANRS_CACHE_TTL) return; if (manrsFetching) { // Wait up to 8s for in-progress fetch for (let i = 0; i < 80; i++) { await new Promise(r => setTimeout(r, 100)); if (manrsAsnSet) return; } return; } manrsFetching = true; try { const html = await new Promise((resolve, reject) => { const opts = { hostname: "www.manrs.org", path: "/netops/participants/", method: "GET", timeout: 15000, headers: { "User-Agent": UA, "Accept": "text/html" } }; const req = https.request(opts, res => { let body = ""; res.on("data", d => { body += d; }); res.on("end", () => resolve(body)); }); req.on("error", reject); req.on("timeout", () => { req.destroy(); reject(new Error("MANRS fetch timeout")); }); req.end(); }); // Extract ASNs from 267490 — may contain multiple space-separated ASNs const set = new Set(); const re = /]*class="asns"[^>]*>([\d\s,]+)<\/td>/gi; for (const m of html.matchAll(re)) { m[1].split(/[\s,]+/).forEach(a => { const n = a.trim(); if (n) set.add(n); }); } if (set.size > 0) { manrsAsnSet = set; manrsLastFetch = Date.now(); console.log("[MANRS] Loaded " + set.size + " participant ASNs from manrs.org"); } } catch (e) { console.warn("[MANRS] Failed to fetch participants:", e.message); } finally { manrsFetching = false; } } function checkManrsMembership(asn) { if (!manrsAsnSet) return { status: "info", participant: "unknown", message: "MANRS data not yet loaded", note: "https://www.manrs.org/netops/participants/" }; const isMember = manrsAsnSet.has(String(asn)); return { status: isMember ? "pass" : "fail", participant: isMember, member_count: manrsAsnSet.size, note: isMember ? "Confirmed MANRS Network Operator participant" : "Not listed as MANRS participant — https://www.manrs.org/beamanrs/", }; } module.exports = { ensureManrsCache, checkManrsMembership };