refactor: extract pdb-org-countries.js, fix Authorization:undefined crash bug
Bug fix (not just code movement): fetchPdbOrgCountries set the Authorization header to `undefined` (via `PEERINGDB_API_KEY ? ... : undefined`) when no API key is configured. Node 22's stricter http header validation throws ERR_HTTP_INVALID_HEADER_VALUE on that instead of omitting the header -- crashes the whole process at startup via an unhandled rejection. Found empirically while trying to boot server.js locally without a real PeeringDB key for the smoke-test harness; the harness works around it with a placeholder key, so this specific path wasn't actually exercised by the diff-based tests (verified the fix by reasoning: conditionally spreading the header key in is equivalent when a key IS present, and simply omits the header when absent, matching intended behavior). pdbOrgCountryMap (a reassigned `let`, not a mutated object) exposed via a pdbOrgState wrapper object, same fix pattern as atlas-probes.js's atlasState -- required updating its two external call sites in server.js (both still inside the still-inline /api/lia/coverage handler). Verified via smoke-test harness (28/28 match). server.js: 3784 -> 3714 lines.
This commit is contained in:
parent
7701edd657
commit
edb47b8986
76
server.js
76
server.js
@ -514,7 +514,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
var probeAsns = new Set(atlasState.cache.asns_with_probes || []);
|
var probeAsns = new Set(atlasState.cache.asns_with_probes || []);
|
||||||
|
|
||||||
var enriched = pdbData.data.map(function(n) {
|
var enriched = pdbData.data.map(function(n) {
|
||||||
var org = pdbOrgCountryMap.get(n.org_id) || {};
|
var org = pdbOrgState.map.get(n.org_id) || {};
|
||||||
var cc = org.country || "";
|
var cc = org.country || "";
|
||||||
return {
|
return {
|
||||||
asn: n.asn,
|
asn: n.asn,
|
||||||
@ -533,7 +533,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
with_probes: enriched.filter(function(n) { return n.has_probe; }).length,
|
with_probes: enriched.filter(function(n) { return n.has_probe; }).length,
|
||||||
without_probes: enriched.filter(function(n) { return !n.has_probe; }).length,
|
without_probes: enriched.filter(function(n) { return !n.has_probe; }).length,
|
||||||
atlas_unique_asns: probeAsns.size,
|
atlas_unique_asns: probeAsns.size,
|
||||||
org_countries_loaded: pdbOrgCountryMap.size,
|
org_countries_loaded: pdbOrgState.map.size,
|
||||||
fetched_at: new Date().toISOString(),
|
fetched_at: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3605,77 +3605,7 @@ ${html}
|
|||||||
|
|
||||||
const { atlasState, fetchAllAtlasProbes } = require("./server/atlas-probes");
|
const { atlasState, fetchAllAtlasProbes } = require("./server/atlas-probes");
|
||||||
|
|
||||||
// ============================================================
|
const { pdbOrgState, fetchPdbOrgCountries } = require("./server/pdb-org-countries");
|
||||||
// PeeringDB Org → Country Cache (for Lia's Paradise)
|
|
||||||
// ============================================================
|
|
||||||
let pdbOrgCountryMap = new Map(); // org_id → { country, name }
|
|
||||||
|
|
||||||
function fetchPdbOrgCountries() {
|
|
||||||
var cacheFile = require("path").join(__dirname, ".pdb-org-cache.json");
|
|
||||||
var fs = require("fs");
|
|
||||||
|
|
||||||
// Try disk cache first (valid for 24h)
|
|
||||||
try {
|
|
||||||
var stat = fs.statSync(cacheFile);
|
|
||||||
var ageHours = (Date.now() - stat.mtimeMs) / 3600000;
|
|
||||||
if (ageHours < 24) {
|
|
||||||
var cached = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
|
|
||||||
pdbOrgCountryMap = new Map(Object.entries(cached));
|
|
||||||
console.log("[PDB-ORG] Loaded " + pdbOrgCountryMap.size + " orgs from disk cache (" + Math.round(ageHours) + "h old)");
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
} catch (_) { /* no cache or invalid */ }
|
|
||||||
|
|
||||||
console.log("[PDB-ORG] Fetching PeeringDB org countries (fresh)...");
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
var chunks = [];
|
|
||||||
var req = require("https").get("https://www.peeringdb.com/api/org?status=ok&depth=0", {
|
|
||||||
headers: {
|
|
||||||
"User-Agent": UA,
|
|
||||||
"Authorization": PEERINGDB_API_KEY ? "Api-Key " + PEERINGDB_API_KEY : undefined,
|
|
||||||
},
|
|
||||||
timeout: 120000,
|
|
||||||
}, function(res) {
|
|
||||||
if (res.statusCode !== 200) {
|
|
||||||
console.error("[PDB-ORG] HTTP " + res.statusCode + " — using stale cache or empty");
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.on("data", function(chunk) { chunks.push(chunk); });
|
|
||||||
res.on("end", function() {
|
|
||||||
try {
|
|
||||||
var body = Buffer.concat(chunks).toString("utf8");
|
|
||||||
var data = JSON.parse(body);
|
|
||||||
if (data && data.data) {
|
|
||||||
pdbOrgCountryMap = new Map();
|
|
||||||
var cacheObj = {};
|
|
||||||
data.data.forEach(function(o) {
|
|
||||||
if (o.id && o.country) {
|
|
||||||
pdbOrgCountryMap.set(o.id, { country: o.country, name: o.name || "" });
|
|
||||||
cacheObj[o.id] = { country: o.country, name: o.name || "" };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Save to disk cache
|
|
||||||
try { fs.writeFileSync(cacheFile, JSON.stringify(cacheObj)); } catch (_) {}
|
|
||||||
console.log("[PDB-ORG] Loaded " + pdbOrgCountryMap.size + " org→country mappings (cached to disk)");
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[PDB-ORG] Parse error:", e.message);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
req.on("error", function(e) {
|
|
||||||
console.error("[PDB-ORG] Fetch error:", e.message);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
req.on("timeout", function() {
|
|
||||||
console.error("[PDB-ORG] Timeout after 120s");
|
|
||||||
req.destroy();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3101;
|
const PORT = process.env.PORT || 3101;
|
||||||
|
|
||||||
|
|||||||
92
server/pdb-org-countries.js
Normal file
92
server/pdb-org-countries.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const https = require("https");
|
||||||
|
const path = require("path");
|
||||||
|
const { UA } = require("./data/constants");
|
||||||
|
const { PEERINGDB_API_KEY } = require("./services/peeringdb");
|
||||||
|
|
||||||
|
// Repo root -- NOT this module's own directory. See hijack-monitoring/store.js
|
||||||
|
// for the same __dirname-fallback fix applied for the same reason.
|
||||||
|
const REPO_ROOT = path.join(__dirname, "..");
|
||||||
|
|
||||||
|
// PeeringDB Org → Country Cache (for Lia's Paradise). Exposed via a mutable
|
||||||
|
// state object (not a bare reassigned export) for the same reason as
|
||||||
|
// atlas-probes.js's atlasState -- the Map itself is reassigned wholesale on
|
||||||
|
// refresh, not just mutated in place.
|
||||||
|
const pdbOrgState = { map: new Map() }; // org_id → { country, name }
|
||||||
|
|
||||||
|
function fetchPdbOrgCountries() {
|
||||||
|
var cacheFile = path.join(REPO_ROOT, ".pdb-org-cache.json");
|
||||||
|
|
||||||
|
// Try disk cache first (valid for 24h)
|
||||||
|
try {
|
||||||
|
var stat = fs.statSync(cacheFile);
|
||||||
|
var ageHours = (Date.now() - stat.mtimeMs) / 3600000;
|
||||||
|
if (ageHours < 24) {
|
||||||
|
var cached = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
|
||||||
|
pdbOrgState.map = new Map(Object.entries(cached));
|
||||||
|
console.log("[PDB-ORG] Loaded " + pdbOrgState.map.size + " orgs from disk cache (" + Math.round(ageHours) + "h old)");
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
} catch (_) { /* no cache or invalid */ }
|
||||||
|
|
||||||
|
console.log("[PDB-ORG] Fetching PeeringDB org countries (fresh)...");
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
var chunks = [];
|
||||||
|
var req = https.get("https://www.peeringdb.com/api/org?status=ok&depth=0", {
|
||||||
|
headers: {
|
||||||
|
"User-Agent": UA,
|
||||||
|
// Bug fix 2026-07-16: a bare `PEERINGDB_API_KEY ? ... : undefined`
|
||||||
|
// sets the Authorization header value to `undefined` when no key is
|
||||||
|
// configured. Node 22's stricter header validation throws
|
||||||
|
// synchronously on that (ERR_HTTP_INVALID_HEADER_VALUE) instead of
|
||||||
|
// omitting the header, crashing the whole process at startup via
|
||||||
|
// this function's unhandled rejection (found empirically while
|
||||||
|
// trying to boot server.js locally without a real PeeringDB key).
|
||||||
|
// Conditionally spread the key in instead so the header key itself
|
||||||
|
// is simply absent when unconfigured.
|
||||||
|
...(PEERINGDB_API_KEY ? { "Authorization": "Api-Key " + PEERINGDB_API_KEY } : {}),
|
||||||
|
},
|
||||||
|
timeout: 120000,
|
||||||
|
}, function(res) {
|
||||||
|
if (res.statusCode !== 200) {
|
||||||
|
console.error("[PDB-ORG] HTTP " + res.statusCode + " — using stale cache or empty");
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.on("data", function(chunk) { chunks.push(chunk); });
|
||||||
|
res.on("end", function() {
|
||||||
|
try {
|
||||||
|
var body = Buffer.concat(chunks).toString("utf8");
|
||||||
|
var data = JSON.parse(body);
|
||||||
|
if (data && data.data) {
|
||||||
|
pdbOrgState.map = new Map();
|
||||||
|
var cacheObj = {};
|
||||||
|
data.data.forEach(function(o) {
|
||||||
|
if (o.id && o.country) {
|
||||||
|
pdbOrgState.map.set(o.id, { country: o.country, name: o.name || "" });
|
||||||
|
cacheObj[o.id] = { country: o.country, name: o.name || "" };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Save to disk cache
|
||||||
|
try { fs.writeFileSync(cacheFile, JSON.stringify(cacheObj)); } catch (_) {}
|
||||||
|
console.log("[PDB-ORG] Loaded " + pdbOrgState.map.size + " org→country mappings (cached to disk)");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[PDB-ORG] Parse error:", e.message);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on("error", function(e) {
|
||||||
|
console.error("[PDB-ORG] Fetch error:", e.message);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
req.on("timeout", function() {
|
||||||
|
console.error("[PDB-ORG] Timeout after 120s");
|
||||||
|
req.destroy();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { pdbOrgState, fetchPdbOrgCountries };
|
||||||
Loading…
x
Reference in New Issue
Block a user