From e690b30e9241e3b719a111145f820eede1dfa62f Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sun, 3 May 2026 18:11:15 -0400 Subject: [PATCH] feat(monitor/frontend): country-centroid plotting for ransomware + internet_outage on globe --- .../frontend/src/lib/countryCentroids.ts | 194 ++++++++++++++++++ .../frontend/src/pages/dashboard/lifecycle.ts | 64 +++++- 2 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts new file mode 100644 index 00000000..2104b40c --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts @@ -0,0 +1,194 @@ +// ©AngelaMos | 2026 +// countryCentroids.ts + +export interface Centroid { + lat: number + lng: number +} + +const ISO_ALIASES: Record = { + UK: 'GB', +} + +export const COUNTRY_CENTROIDS: Record = { + AE: { lat: 24.2762, lng: 53.9882 }, + AF: { lat: 33.9024, lng: 67.8432 }, + AL: { lat: 41.1566, lng: 20.1623 }, + AM: { lat: 39.9947, lng: 45.0442 }, + AO: { lat: -11.8974, lng: 17.86 }, + AQ: { lat: -76.6353, lng: 0.0 }, + AR: { lat: -37.0911, lng: -63.5219 }, + AT: { lat: 47.7354, lng: 13.2298 }, + AU: { lat: -24.852, lng: 133.4542 }, + AZ: { lat: 40.0655, lng: 47.6827 }, + BA: { lat: 43.9419, lng: 17.6749 }, + BD: { lat: 23.5587, lng: 90.3786 }, + BE: { lat: 50.5023, lng: 4.3351 }, + BF: { lat: 12.3635, lng: -1.6467 }, + BG: { lat: 42.7347, lng: 25.4693 }, + BI: { lat: -3.4242, lng: 29.8886 }, + BJ: { lat: 9.1889, lng: 2.2847 }, + BN: { lat: 4.7277, lng: 114.8274 }, + BO: { lat: -16.3175, lng: -63.5444 }, + BR: { lat: -14.2619, lng: -54.3586 }, + BS: { lat: 24.4601, lng: -77.9716 }, + BT: { lat: 27.5079, lng: 90.459 }, + BW: { lat: -22.2452, lng: 24.6638 }, + BY: { lat: 53.7443, lng: 27.9466 }, + BZ: { lat: 17.1935, lng: -88.668 }, + CA: { lat: 56.7978, lng: -98.3406 }, + CD: { lat: -4.0006, lng: 21.6782 }, + CF: { lat: 6.705, lng: 20.9168 }, + CG: { lat: -0.6549, lng: 14.7734 }, + CH: { lat: 46.8039, lng: 8.2327 }, + CI: { lat: 7.4312, lng: -5.5825 }, + CL: { lat: -35.7182, lng: -71.3148 }, + CM: { lat: 7.2935, lng: 12.2508 }, + CN: { lat: 36.8706, lng: 104.3508 }, + CO: { lat: 4.0696, lng: -72.9336 }, + CR: { lat: 9.7211, lng: -84.244 }, + CU: { lat: 21.522, lng: -79.5765 }, + CY: { lat: 34.8725, lng: 33.1308 }, + CZ: { lat: 49.8363, lng: 15.5466 }, + DE: { lat: 51.1428, lng: 10.5028 }, + DJ: { lat: 11.8133, lng: 42.4898 }, + DK: { lat: 56.2804, lng: 9.5011 }, + DO: { lat: 18.7417, lng: -70.1315 }, + DZ: { lat: 28.0879, lng: 1.6576 }, + EC: { lat: -1.7891, lng: -78.1007 }, + EE: { lat: 58.5428, lng: 25.7357 }, + EG: { lat: 26.7928, lng: 30.7831 }, + EH: { lat: 24.3281, lng: -12.8643 }, + ER: { lat: 15.2269, lng: 39.7022 }, + ES: { lat: 39.8476, lng: -3.1767 }, + ET: { lat: 9.1907, lng: 40.3718 }, + FI: { lat: 65.0053, lng: 26.0808 }, + FJ: { lat: -17.814, lng: 178.0016 }, + FK: { lat: -51.7, lng: -59.475 }, + FR: { lat: 46.7459, lng: 1.7535 }, + GA: { lat: -0.826, lng: 11.6117 }, + GB: { lat: 54.2975, lng: -2.2342 }, + GE: { lat: 42.3088, lng: 43.2965 }, + GH: { lat: 7.9044, lng: -1.0921 }, + GL: { lat: 71.8409, lng: -42.7528 }, + GM: { lat: 13.5034, lng: -15.3432 }, + GN: { lat: 9.9476, lng: -11.4812 }, + GQ: { lat: 1.647, lng: 10.2953 }, + GR: { lat: 39.1185, lng: 23.3771 }, + GT: { lat: 15.7773, lng: -90.2271 }, + GW: { lat: 11.8343, lng: -15.189 }, + GY: { lat: 4.8176, lng: -58.9748 }, + HN: { lat: 14.495, lng: -86.2503 }, + HR: { lat: 44.4919, lng: 16.5237 }, + HT: { lat: 18.9733, lng: -73.0415 }, + HU: { lat: 47.1917, lng: 19.4564 }, + ID: { lat: -2.0151, lng: 122.0041 }, + IE: { lat: 53.4005, lng: -8.005 }, + IL: { lat: 31.3894, lng: 35.0509 }, + IN: { lat: 21.7298, lng: 82.7896 }, + IQ: { lat: 33.2421, lng: 43.6802 }, + IR: { lat: 32.3956, lng: 53.7129 }, + IS: { lat: 65.0116, lng: -18.968 }, + IT: { lat: 42.5121, lng: 12.6151 }, + JM: { lat: 18.1127, lng: -77.2687 }, + JO: { lat: 31.2881, lng: 37.059 }, + JP: { lat: 36.2041, lng: 135.6614 }, + KE: { lat: 0.4146, lng: 37.8743 }, + KG: { lat: 41.2889, lng: 74.8624 }, + KH: { lat: 12.5286, lng: 104.9813 }, + KP: { lat: 40.3272, lng: 127.5228 }, + KR: { lat: 36.5011, lng: 127.7929 }, + KW: { lat: 29.2926, lng: 47.4924 }, + KZ: { lat: 48.0238, lng: 66.9132 }, + LA: { lat: 18.1729, lng: 103.8403 }, + LB: { lat: 33.867, lng: 35.8689 }, + LK: { lat: 7.8962, lng: 80.7416 }, + LR: { lat: 6.4484, lng: -9.4892 }, + LS: { lat: -29.6463, lng: 28.1622 }, + LT: { lat: 55.1391, lng: 23.822 }, + LU: { lat: 49.7854, lng: 5.9584 }, + LV: { lat: 56.7926, lng: 24.6163 }, + LY: { lat: 26.3587, lng: 17.2421 }, + MA: { lat: 28.5904, lng: -9.0725 }, + MD: { lat: 46.9777, lng: 28.322 }, + ME: { lat: 42.7007, lng: 19.3949 }, + MG: { lat: -18.821, lng: 46.8654 }, + MK: { lat: 41.5815, lng: 21.7078 }, + ML: { lat: 17.5355, lng: -3.9503 }, + MM: { lat: 19.1345, lng: 96.7416 }, + MN: { lat: 46.8224, lng: 103.762 }, + MR: { lat: 21.0063, lng: -10.9934 }, + MW: { lat: -13.0159, lng: 34.23 }, + MX: { lat: 23.6298, lng: -101.9699 }, + MY: { lat: 3.8506, lng: 114.4226 }, + MZ: { lat: -18.5296, lng: 35.4775 }, + NA: { lat: -22.9934, lng: 18.4093 }, + NC: { lat: -21.2528, lng: 165.5748 }, + NE: { lat: 17.5659, lng: 8.0994 }, + NG: { lat: 9.0533, lng: 8.6344 }, + NI: { lat: 12.8716, lng: -85.4079 }, + NL: { lat: 52.1571, lng: 5.2035 }, + NP: { lat: 28.4103, lng: 84.1316 }, + NZ: { lat: -38.0695, lng: 175.5765 }, + OM: { lat: 20.7879, lng: 55.904 }, + PA: { lat: 8.4161, lng: -80.1042 }, + PE: { lat: -9.2026, lng: -75.038 }, + PG: { lat: -6.6263, lng: 145.9009 }, + PH: { lat: 15.521, lng: 122.0325 }, + PK: { lat: 30.4125, lng: 69.3558 }, + PL: { lat: 51.9395, lng: 19.0523 }, + PR: { lat: 18.2336, lng: -66.4167 }, + PS: { lat: 31.943, lng: 35.2365 }, + PT: { lat: 39.5594, lng: -7.9578 }, + PY: { lat: -23.4456, lng: -58.489 }, + QA: { lat: 25.3355, lng: 51.1753 }, + RO: { lat: 45.9547, lng: 24.9234 }, + RS: { lat: 44.2085, lng: 20.9079 }, + RU: { lat: 59.4247, lng: 103.6441 }, + RW: { lat: -2.0263, lng: 29.9205 }, + SA: { lat: 24.2544, lng: 45.1495 }, + SB: { lat: -7.9292, lng: 159.0643 }, + SD: { lat: 15.1146, lng: 30.1734 }, + SE: { lat: 62.234, lng: 17.4654 }, + SI: { lat: 46.1524, lng: 15.1315 }, + SK: { lat: 48.665, lng: 19.7191 }, + SL: { lat: 8.4165, lng: -11.7383 }, + SN: { lat: 14.4652, lng: -14.5465 }, + SO: { lat: 5.1707, lng: 46.0575 }, + SR: { lat: 3.9215, lng: -56.0014 }, + SS: { lat: 7.8786, lng: 29.5925 }, + SV: { lat: 13.7866, lng: -88.9095 }, + SY: { lat: 34.7714, lng: 39.0252 }, + SZ: { lat: -26.473, lng: 31.3741 }, + TD: { lat: 15.4158, lng: 18.7136 }, + TF: { lat: -49.2, lng: 69.64 }, + TG: { lat: 8.4738, lng: 0.9077 }, + TH: { lat: 13.0546, lng: 101.4825 }, + TJ: { lat: 38.8492, lng: 71.2111 }, + TL: { lat: -8.8333, lng: 126.1523 }, + TM: { lat: 39.0111, lng: 59.5243 }, + TN: { lat: 33.8288, lng: 9.5066 }, + TR: { lat: 38.9309, lng: 35.4824 }, + TT: { lat: 10.445, lng: -61.4225 }, + TW: { lat: 23.633, lng: 121.0287 }, + TZ: { lat: -6.3355, lng: 34.8283 }, + UA: { lat: 48.8142, lng: 31.0832 }, + UG: { lat: 1.4033, lng: 32.3077 }, + US: { lat: 37.2345, lng: -95.8259 }, + UY: { lat: -32.5312, lng: -55.8183 }, + UZ: { lat: 41.3659, lng: 64.4922 }, + VE: { lat: 6.4434, lng: -66.5316 }, + VN: { lat: 15.9759, lng: 105.7529 }, + VU: { lat: -15.1833, lng: 166.9496 }, + XK: { lat: 42.5596, lng: 20.9229 }, + YE: { lat: 15.793, lng: 47.8567 }, + ZA: { lat: -28.4552, lng: 24.5875 }, + ZM: { lat: -13.0997, lng: 27.6868 }, + ZW: { lat: -18.8897, lng: 29.057 }, +} + +export function getCentroid(iso2: string): Centroid | null { + if (!iso2) return null + const code = ISO_ALIASES[iso2] ?? iso2 + return COUNTRY_CENTROIDS[code] ?? null +} diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/lifecycle.ts b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/lifecycle.ts index 20cc1092..98719391 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/lifecycle.ts +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/lifecycle.ts @@ -6,11 +6,16 @@ import { useEffect, useRef } from 'react' import { SNAPSHOT_KEY, type Snapshot, useSnapshot } from '@/api/snapshot' import { browserDriver, createDashboardWS, type WSEvent } from '@/api/ws' import { unlockOnFirstGesture } from '@/lib/audio' +import { getCentroid } from '@/lib/countryCentroids' import { type CveEvent, useCveStore } from '@/stores/cve' import { useGlobeEvents } from '@/stores/globeEvents' import { type KevEntry, useKevStore } from '@/stores/kev' import { usePrices } from '@/stores/prices' -import { type RansomwareVictim, useRansomwareStore } from '@/stores/ransomware' +import { + type RansomwareVictim, + useRansomwareStore, + victimKey, +} from '@/stores/ransomware' import { useTicker } from '@/stores/ticker' const ALL_TOPICS: readonly string[] = [ @@ -67,6 +72,16 @@ interface GdeltSpikePayload { zscore: number } +interface OutagePayload { + id: string + startDate?: string + endDate?: string | null + locations?: string[] + asns?: number[] + reason?: string + outageType?: string +} + export function useDashboardLifecycle(): void { const { data: snapshot, isSuccess } = useSnapshot() const queryClient = useQueryClient() @@ -140,8 +155,10 @@ function routeEvent(ev: WSEvent, queryClient: QueryClient): void { case 'gdelt_spike': handleGdelt(data as GdeltSpikePayload) break - case 'space_weather': case 'internet_outage': + handleOutage(data as OutagePayload, queryClient) + break + case 'space_weather': case 'bgp_hijack': case 'scan_firehose': mergeIntoSnapshot(queryClient, ev.topic, data) @@ -164,6 +181,43 @@ function handleKev(p: KevEntry): void { function handleRansomware(p: RansomwareVictim): void { if (!p.post_title) return useRansomwareStore.getState().push(p) + pushRansomwarePoint(p) +} + +function pushRansomwarePoint(p: RansomwareVictim): void { + if (!p.country) return + const c = getCentroid(p.country) + if (!c) return + useGlobeEvents.getState().pushPoint({ + id: `rw-${victimKey(p)}`, + type: 'ransomware', + lat: c.lat, + lng: c.lng, + emittedAt: Date.now(), + meta: { group_name: p.group_name, post_title: p.post_title }, + }) +} + +function handleOutage(p: OutagePayload, queryClient: QueryClient): void { + pushOutagePoints(p) + mergeIntoSnapshot(queryClient, 'internet_outage', p) +} + +function pushOutagePoints(p: OutagePayload): void { + if (!p.id || !Array.isArray(p.locations)) return + const now = Date.now() + for (const loc of p.locations) { + const c = getCentroid(loc) + if (!c) continue + useGlobeEvents.getState().pushPoint({ + id: `outage-${p.id}-${loc}`, + type: 'outage', + lat: c.lat, + lng: c.lng, + emittedAt: now, + meta: { reason: p.reason, type: p.outageType }, + }) + } } function handleCoinbase(p: CoinbaseTickPayload): void { @@ -278,4 +332,10 @@ function seedGlobeFromSnapshot(snap: Snapshot): void { emittedAt: Date.now(), }) } + + const rw = snap.ransomware_victim as RansomwareVictim | undefined + if (rw) pushRansomwarePoint(rw) + + const outage = snap.internet_outage as OutagePayload | undefined + if (outage) pushOutagePoints(outage) }