feat(monitor/frontend): country-centroid plotting for ransomware + internet_outage on globe
This commit is contained in:
parent
0a41102e75
commit
e690b30e92
|
|
@ -0,0 +1,194 @@
|
|||
// ©AngelaMos | 2026
|
||||
// countryCentroids.ts
|
||||
|
||||
export interface Centroid {
|
||||
lat: number
|
||||
lng: number
|
||||
}
|
||||
|
||||
const ISO_ALIASES: Record<string, string> = {
|
||||
UK: 'GB',
|
||||
}
|
||||
|
||||
export const COUNTRY_CENTROIDS: Record<string, Centroid> = {
|
||||
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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue