/* global React, Icon, useLiveThreatData, geoForVendor, severityFor, REGIONS, useCountUp, forceResync */
const { useState: useS_dm, useEffect: useE_dm, useMemo: useM_dm } = React;
/* ──────────────────────────────────────────────
SOC PANEL — backed by real CISA KEV data
────────────────────────────────────────────── */
function SocPanel() {
const live = useLiveThreatData();
const [tick, setTick] = useS_dm(0);
useE_dm(() => {
const id = setInterval(() => setTick((t) => t + 1), 1800);
return () => clearInterval(id);
}, []);
// Count-up animation on the headline numbers
const totalCount = useCountUp(live.loading ? 0 : live.total);
const ransomCount = useCountUp(live.loading ? 0 : live.ransomware);
const recent30Count = useCountUp(live.loading ? 0 : live.last30d);
const now = Date.now();
const recent = live.recent || [];
// Round-robin by region to guarantee geographic diversity — always plot at
// least one ping per inhabited region per cycle. CISA KEV is dominated by
// US vendors, so without this the map looks like only the US is attacked.
const slice = useM_dm(() => {
if (!recent.length) return [];
// Bucket CVEs by region using vendor mapping
const byRegion = {};
recent.forEach((item) => {
const geo = geoForVendor(item.vendorProject);
const code = (geo && geo.region) || "NA";
(byRegion[code] = byRegion[code] || []).push(item);
});
const cursors = {};
const out = [];
const n = 9; // total simultaneous pings
for (let i = 0; i < n; i++) {
const reg = REGIONS[(tick + i) % REGIONS.length];
const bucket = byRegion[reg.code] || [];
cursors[reg.code] = (cursors[reg.code] || 0) + 1;
let geo, sev, item;
if (bucket.length) {
item = bucket[(cursors[reg.code] + tick) % bucket.length];
geo = geoForVendor(item.vendorProject) || reg;
sev = severityFor(item, now);
} else {
// No CVEs in current data for this region — plot a "regional activity"
// ping anchored at the region centroid so the map shows global presence.
geo = reg;
sev = "low";
}
// Tight jitter so identical-region pings don't overlap
const jx = ((i * 37 + tick * 11) % 7) - 3;
const jy = ((i * 19 + tick * 7) % 5) - 2;
out.push({
id: (item ? item.cveID : reg.code) + ":" + i + ":" + tick,
x: Math.max(4, Math.min(96, (geo.x ?? reg.x) + jx)),
y: Math.max(8, Math.min(82, (geo.y ?? reg.y) + jy)),
sev,
});
}
return out;
}, [recent, tick]);
// Local time + timezone abbreviation — reads from the user's system clock,
// so it auto-adapts: BRT for visitors in Brazil, EST for NY, etc.
// No IP lookup needed (and no consent banner).
const localTime = new Date().toLocaleTimeString("pt-BR", { hour12: false });
const tzAbbr = (() => {
try {
const parts = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(new Date());
return (parts.find((p) => p.type === "timeZoneName") || {}).value || "UTC";
} catch { return ""; }
})();
const ringPct = live.loading ? 0 :
Math.max(8, Math.min(98, Math.round(100 - (live.last7d / Math.max(1, live.last30d)) * 100)));
const ringDisplay = useCountUp(ringPct);
const sourceLabel =
live.source === "cisa" ? "CISA · LIVE" :
live.source === "cache" ? "CISA · CACHE" :
live.source === "snapshot" ? "CISA · SNAPSHOT" :
"CARREGANDO";
const syncWhen = live.fetchedAt
? new Date(live.fetchedAt).toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", second: "2-digit" })
: "—";
const sevCount = { high: 0, med: 0, low: 0 };
recent.forEach((it) => { sevCount[severityFor(it, now)]++; });
return (
{slice.map((t) => (
))}
BRZ‑01
{live.loading && SINCRONIZANDO CISA KEV …}
);
}
function Ring({ percent }) {
const r = 28, c = 2 * Math.PI * r;
const off = c - (c * percent) / 100;
return (
);
}
function WorldMap() {
const cols = 38, rows = 14;
const M = [
"00001111110000000111111111111100000000",
"00111111111111000111111111111111100000",
"01111111111111101111111111111111110000",
"11111111111111101111111111111111111100",
"01111111111110001111111111111111111100",
"00111111111100000111111111111111111000",
"00011111111000000011111111111111110000",
"00001111110000000001111111111111100000",
"00000111100000000000111111111111000000",
"00000011000000000000011111111110000000",
"00000011000000000000000111111100000000",
"00000001000000000000000011110000000000",
"00000000000000000000000001000000000000",
"00000000000000000000000000000000000000",
];
const dots = [];
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (M[r] && M[r][c] === "1") {
dots.push({ x: (c + 0.5) * (100 / cols), y: (r + 0.5) * (100 / rows) });
}
}
}
return (
);
}
/* ──────────────────────────────────────────────
DASHMOCK — Cyber Investigator dashboard mock
(uses real CVE rows in the timeline)
────────────────────────────────────────────── */
function DashMock() {
const live = useLiveThreatData();
const [t, setT] = useS_dm(0);
useE_dm(() => { const id = setInterval(() => setT((x) => x + 1), 900); return () => clearInterval(id); }, []);
const bars = Array.from({ length: 24 }).map((_, i) => {
const h = 18 + ((Math.sin((i + t) * 0.5) + 1) / 2) * 70 + (i % 5 === 0 ? 12 : 0);
return Math.min(100, h);
});
const events = (live.recent || []).slice(0, 5).map((e) => ({
t: e.dateAdded ? e.dateAdded.slice(0, 10) : "—",
lvl: e.knownRansomwareCampaignUse === "Known" ? "HIGH" :
(Date.now() - new Date(e.dateAdded).getTime()) < 30 * 86400000 ? "MED" : "OK",
cve: e.cveID,
msg: `${e.vendorProject} · ${e.product}`,
who: "CISA KEV",
}));
const total = live.loading ? "—" : live.total.toLocaleString("pt-BR");
const trend = live.last7d ? `▲ ${live.last7d} novas (7d)` : "estável";
return (
CVES EXPLORADAS (CISA)
{total}
{trend}
↳ catálogo oficial · atualizado em tempo real
Atividade ilustrativa · 30 min
linha de base 42 ev/m
{bars.map((h, i) => (
80 ? "hot" : h > 55 ? "warm" : "")}
style={{ height: h + "%" }}
/>
))}
CVEs mais recentes · CISA KEV
filtros: alta · médio
{events.length === 0 && (
- sincronizando feed CISA…
)}
{events.map((e, i) => (
-
{e.t}
{e.lvl}
{e.cve} · {e.msg}
{e.who}
))}
);
}
/* ──────────────────────────────────────────────
HERO TICKER — pulls real CVE IDs when available
────────────────────────────────────────────── */
function HeroTicker() {
const live = useLiveThreatData();
const fallback = [
"edge/sa-east-1 · TLS handshake OK",
"leak-watch · 0 novas exposições",
"iam-sentinel · 1 permissão revisada",
];
const items = (live.recent && live.recent.length)
? live.recent.slice(0, 14).map((e) => `${e.cveID} · ${e.vendorProject} ${e.product}`)
: fallback;
return (
{items.concat(items).map((t, i) => (
{t}
))}
fonte: CISA Known Exploited Vulnerabilities Catalog · atualizado a cada visita
);
}
Object.assign(window, { SocPanel, DashMock, HeroTicker, Ring });