From cf38f88efdb92c363368694251cb1df1d17a5e15 Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sun, 3 May 2026 19:11:12 -0400 Subject: [PATCH] fix(monitor/frontend): supplementary centroids (HK et al) + bgp schema lenient (victimAsns nullable, dedup geo/threat types) --- .../frontend/src/api/types/geo.types.ts | 28 --------------- .../frontend/src/api/types/threat.types.ts | 27 ++++++++++++++ .../frontend/src/lib/countryCentroids.ts | 35 ++++++++++++++++++- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/geo.types.ts b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/geo.types.ts index 7e51373e..5633a0fe 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/geo.types.ts +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/geo.types.ts @@ -36,29 +36,6 @@ export const internetOutageSchema = z.object({ export type InternetOutage = z.infer -export const bgpEnrichmentSchema = z.object({ - country: z.string().optional(), - abuse_confidence: z.number().optional(), - isp: z.string().optional(), - checked_ip: z.string().optional(), -}) - -export type BgpEnrichment = z.infer - -export const bgpHijackSchema = z.object({ - id: z.number(), - detectedAt: z.string().optional(), - startedAt: z.string().optional(), - duration: z.number().optional(), - confidenceScore: z.number().optional(), - hijackerAsn: z.number().optional(), - victimAsns: z.array(z.number()).nullable().optional(), - prefixes: z.array(z.string()).optional(), - enrichment: bgpEnrichmentSchema.optional(), -}) - -export type BgpHijack = z.infer - export const isValidIssPosition = (data: unknown): data is IssPosition => { if (data === null || data === undefined || typeof data !== 'object') return false return issPositionSchema.safeParse(data).success @@ -75,8 +52,3 @@ export const isValidInternetOutage = (data: unknown): data is InternetOutage => if (data === null || data === undefined || typeof data !== 'object') return false return internetOutageSchema.safeParse(data).success } - -export const isValidBgpHijack = (data: unknown): data is BgpHijack => { - if (data === null || data === undefined || typeof data !== 'object') return false - return bgpHijackSchema.safeParse(data).success -} diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/threat.types.ts b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/threat.types.ts index ece0d22f..acae5284 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/threat.types.ts +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/api/types/threat.types.ts @@ -30,6 +30,7 @@ export const dshieldSourceSchema = z.object({ source: z.string(), reports: z.number(), targets: z.number(), + country: z.string().optional(), }) export type DShieldSource = z.infer @@ -65,3 +66,29 @@ export const isValidDShieldData = (data: unknown): data is DShieldData => { if (data === null || data === undefined || typeof data !== 'object') return false return dshieldDataSchema.safeParse(data).success } + +const bgpHijackEnrichmentSchema = z.object({ + country: z.string().optional(), + abuse_confidence: z.number().optional(), + isp: z.string().optional(), + checked_ip: z.string().optional(), +}) + +export const bgpHijackSchema = z.object({ + id: z.number(), + detectedAt: z.string().optional(), + startedAt: z.string().optional(), + duration: z.number().optional(), + confidenceScore: z.number().optional(), + hijackerAsn: z.number().optional(), + victimAsns: z.array(z.number()).nullable().optional(), + prefixes: z.array(z.string()).optional(), + enrichment: bgpHijackEnrichmentSchema.optional(), +}) + +export type BgpHijack = z.infer + +export const isValidBgpHijack = (data: unknown): data is BgpHijack => { + if (data === null || data === undefined || typeof data !== 'object') return false + return bgpHijackSchema.safeParse(data).success +} 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 index 2104b40c..88878957 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/lib/countryCentroids.ts @@ -10,6 +10,39 @@ const ISO_ALIASES: Record = { UK: 'GB', } +const SUPPLEMENTARY_CENTROIDS: Record = { + HK: { lat: 22.3193, lng: 114.1694 }, + MO: { lat: 22.1987, lng: 113.5439 }, + SG: { lat: 1.3521, lng: 103.8198 }, + BH: { lat: 26.0667, lng: 50.5577 }, + MT: { lat: 35.9375, lng: 14.3754 }, + LI: { lat: 47.166, lng: 9.555 }, + AD: { lat: 42.5063, lng: 1.5218 }, + MC: { lat: 43.7384, lng: 7.4246 }, + SM: { lat: 43.9424, lng: 12.4578 }, + VA: { lat: 41.9029, lng: 12.4534 }, + MV: { lat: 3.2028, lng: 73.2207 }, + BB: { lat: 13.1939, lng: -59.5432 }, + BS: { lat: 25.0343, lng: -77.3963 }, + BM: { lat: 32.3078, lng: -64.7505 }, + KY: { lat: 19.3133, lng: -81.2546 }, + JM: { lat: 18.1096, lng: -77.2975 }, + AW: { lat: 12.5211, lng: -69.9683 }, + CW: { lat: 12.1696, lng: -68.99 }, + AG: { lat: 17.0608, lng: -61.7964 }, + TT: { lat: 10.6918, lng: -61.2225 }, + MU: { lat: -20.3484, lng: 57.5522 }, + SC: { lat: -4.6796, lng: 55.492 }, + CV: { lat: 16.5388, lng: -23.0418 }, + ST: { lat: 0.1864, lng: 6.6131 }, + KM: { lat: -11.6455, lng: 43.3333 }, + GD: { lat: 12.1165, lng: -61.679 }, + LC: { lat: 13.9094, lng: -60.9789 }, + VC: { lat: 13.2528, lng: -61.197 }, + KN: { lat: 17.3578, lng: -62.783 }, + DM: { lat: 15.415, lng: -61.371 }, +} + export const COUNTRY_CENTROIDS: Record = { AE: { lat: 24.2762, lng: 53.9882 }, AF: { lat: 33.9024, lng: 67.8432 }, @@ -190,5 +223,5 @@ export const COUNTRY_CENTROIDS: Record = { export function getCentroid(iso2: string): Centroid | null { if (!iso2) return null const code = ISO_ALIASES[iso2] ?? iso2 - return COUNTRY_CENTROIDS[code] ?? null + return COUNTRY_CENTROIDS[code] ?? SUPPLEMENTARY_CENTROIDS[code] ?? null }