mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-10 20:50:25 +02:00
feat: Telegram OSINT map layer, Osiris intel ports, and maritime settings
Add Telegram OSINT with hourly incremental t.me scraping, metro geocoding separate from news centroids, threat-intercept popup UI with inline media, and HTML markers above alert boxes so pins stay clickable. Expose GFW_API_TOKEN in onboarding and Settings Maritime; harden GFW/CCTV/geo fetchers. Port Osiris- derived recon, SCM, entity graph, malware/cyber feeds, sanctions, and submarine cable layers with tests and documentation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { VIEWPORT_COMMITTED_EVENT } from '@/components/map/hooks/useViewportBounds';
|
||||
import { setLiveDataBounds } from '@/lib/liveDataViewport';
|
||||
|
||||
describe('viewport fast refetch wiring', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
setLiveDataBounds({ south: 10, west: 20, north: 12, east: 22 });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setLiveDataBounds(null);
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('VIEWPORT_COMMITTED_EVENT is a stable custom event name', () => {
|
||||
expect(VIEWPORT_COMMITTED_EVENT).toBe('shadowbroker:viewport-committed');
|
||||
const handler = vi.fn();
|
||||
window.addEventListener(VIEWPORT_COMMITTED_EVENT, handler);
|
||||
window.dispatchEvent(new CustomEvent(VIEWPORT_COMMITTED_EVENT));
|
||||
expect(handler).toHaveBeenCalledTimes(1);
|
||||
window.removeEventListener(VIEWPORT_COMMITTED_EVENT, handler);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { sanitizeSubmarineCables } from '@/lib/submarineCables';
|
||||
|
||||
describe('sanitizeSubmarineCables', () => {
|
||||
it('removes synthetic corridor overlays', () => {
|
||||
const out = sanitizeSubmarineCables({
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: { name: 'SEA-ME-WE Corridor' },
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[-5, 51],
|
||||
[73, 17],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: { name: 'FEA' },
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[32, 30],
|
||||
[33, 29],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(out.features).toHaveLength(1);
|
||||
expect(out.features[0].properties?.name).toBe('FEA');
|
||||
});
|
||||
|
||||
it('splits trans-ocean jumps into separate segments', () => {
|
||||
const out = sanitizeSubmarineCables({
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: { name: 'Test Pacific' },
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[-120, 35],
|
||||
[-125, 36],
|
||||
[100, 13],
|
||||
[101, 12],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const geom = out.features[0].geometry;
|
||||
expect(geom?.type).toBe('MultiLineString');
|
||||
if (geom?.type === 'MultiLineString') {
|
||||
expect(geom.coordinates).toHaveLength(2);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
applyTelegramAlertAvoidance,
|
||||
buildTelegramOsintGeoJSON,
|
||||
telegramClusterKey,
|
||||
telegramClusterNearNewsAlert,
|
||||
telegramMapPinCoords,
|
||||
TELEGRAM_ALERT_AVOID_METERS,
|
||||
} from '@/components/map/geoJSONBuilders';
|
||||
|
||||
describe('telegramMapPinCoords', () => {
|
||||
it('stays on the geocoded city when no threat alert overlaps', () => {
|
||||
const [lat, lng] = telegramMapPinCoords(31.046, 34.851, false);
|
||||
expect(lat).toBe(31.046);
|
||||
expect(lng).toBe(34.851);
|
||||
});
|
||||
|
||||
it('nudges ~5 mi northeast only when avoiding an alert', () => {
|
||||
const [lat, lng] = telegramMapPinCoords(31.046, 34.851, true);
|
||||
expect(lat).toBeGreaterThan(31.046);
|
||||
expect(lng).toBeGreaterThan(34.851);
|
||||
const toRad = (deg: number) => (deg * Math.PI) / 180;
|
||||
const dLat = toRad(lat - 31.046);
|
||||
const meters = 6371000 * dLat;
|
||||
expect(meters).toBeGreaterThan(4_000);
|
||||
expect(meters).toBeLessThan(TELEGRAM_ALERT_AVOID_METERS + 2_000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('telegramClusterNearNewsAlert', () => {
|
||||
it('detects news on the same city grid', () => {
|
||||
const news = [{ coords: [31.046, 34.851] as [number, number] }];
|
||||
expect(telegramClusterNearNewsAlert(31.049, 34.849, news)).toBe(true);
|
||||
expect(telegramClusterNearNewsAlert(50.45, 30.52, news)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('telegramClusterKey', () => {
|
||||
it('groups nearby coordinates to the same city bucket', () => {
|
||||
expect(telegramClusterKey(50.451, 30.521)).toBe(telegramClusterKey(50.449, 30.519));
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildTelegramOsintGeoJSON', () => {
|
||||
it('places the dot on the geocoded city by default', () => {
|
||||
const geo = buildTelegramOsintGeoJSON({
|
||||
posts: [
|
||||
{
|
||||
id: 'tg-1',
|
||||
title: 'Strike near Kyiv',
|
||||
coords: [50.45, 30.52],
|
||||
},
|
||||
],
|
||||
});
|
||||
const feature = geo?.features[0];
|
||||
expect(feature).toBeTruthy();
|
||||
const [lng, lat] = feature!.geometry!.coordinates as [number, number];
|
||||
expect(lat).toBeCloseTo(50.45, 2);
|
||||
expect(lng).toBeCloseTo(30.52, 2);
|
||||
});
|
||||
|
||||
it('merges posts in the same city into one pin', () => {
|
||||
const geo = buildTelegramOsintGeoJSON({
|
||||
posts: [
|
||||
{ id: 'a', title: 'Post A', coords: [50.45, 30.52] },
|
||||
{ id: 'b', title: 'Post B', coords: [50.451, 30.521] },
|
||||
{ id: 'c', title: 'Post C', coords: [48.0, 37.8] },
|
||||
],
|
||||
});
|
||||
expect(geo?.features).toHaveLength(2);
|
||||
const kyiv = geo?.features.find((f) => f.properties?.post_count === 2);
|
||||
expect(kyiv).toBeTruthy();
|
||||
expect(kyiv?.properties?.id).toBe(telegramClusterKey(50.45, 30.52));
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyTelegramAlertAvoidance', () => {
|
||||
it('offsets only clusters that share a grid cell with a news alert', () => {
|
||||
const geo = buildTelegramOsintGeoJSON({
|
||||
posts: [
|
||||
{ id: 'il', title: 'Israel post', coords: [31.046, 34.851] },
|
||||
{ id: 'ua', title: 'Kyiv post', coords: [50.45, 30.52] },
|
||||
],
|
||||
});
|
||||
const placed = applyTelegramAlertAvoidance(geo, [{ coords: [31.046, 34.851] }]);
|
||||
const israel = placed?.features.find((f) => f.properties?.id === telegramClusterKey(31.046, 34.851));
|
||||
const kyiv = placed?.features.find((f) => f.properties?.id === telegramClusterKey(50.45, 30.52));
|
||||
const [ilLng, ilLat] = israel!.geometry!.coordinates as [number, number];
|
||||
const [uaLng, uaLat] = kyiv!.geometry!.coordinates as [number, number];
|
||||
expect(ilLat).toBeGreaterThan(31.046);
|
||||
expect(uaLat).toBeCloseTo(50.45, 2);
|
||||
expect(uaLng).toBeCloseTo(30.52, 2);
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,10 @@ import {
|
||||
coarsenViewBounds,
|
||||
expandBoundsToRadius,
|
||||
} from '@/lib/viewportPrivacy';
|
||||
import {
|
||||
liveDataBoundsKey,
|
||||
setLiveDataBounds,
|
||||
} from '@/lib/liveDataViewport';
|
||||
|
||||
describe('viewport privacy helper', () => {
|
||||
it('coarsens narrow bounds outward without clipping the original view', () => {
|
||||
@@ -45,6 +49,14 @@ describe('viewport privacy helper', () => {
|
||||
expect(b).toBe(a);
|
||||
});
|
||||
|
||||
it('liveDataBoundsKey matches quantized fetch params and clears for world view', () => {
|
||||
setLiveDataBounds({ south: 33.6, west: -84.5, north: 33.8, east: -84.2 });
|
||||
expect(liveDataBoundsKey()).toBe('33,-85,34,-84');
|
||||
|
||||
setLiveDataBounds(null);
|
||||
expect(liveDataBoundsKey()).toBeNull();
|
||||
});
|
||||
|
||||
it('expands bounds to a fixed preload radius around the current view center', () => {
|
||||
const original = {
|
||||
south: 39.55,
|
||||
|
||||
Reference in New Issue
Block a user