{headline}
+ + {detail ? ( +{detail}
+ ) : null} + +From af9b3d08cc23ea397e89741a7cf781615d2c2eb7 Mon Sep 17 00:00:00 2001
From: BigBodyCobain <43977454+BigBodyCobain@users.noreply.github.com>
Date: Mon, 8 Jun 2026 21:04:08 -0600
Subject: [PATCH] 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 {detail}
+ );
+ } else if (post.embed_url) {
+ media = (
+
+ );
+ }
+
+ if (!media) return null;
+
+ return (
+
{headline}
+
+ {detail ? (
+
OpenSky Network and AIS Stream are the free keys that make ShadowBroker - useful immediately: live aircraft and vessel tracking. Paste them below or - use Settings later; secrets stay on the local backend. + useful immediately: live aircraft and vessel tracking. Global Fishing Watch + unlocks the fishing-activity layer. Paste them below or use Settings later; + secrets stay on the local backend.
@@ -578,6 +599,7 @@ const OnboardingModal = React.memo(function OnboardingModal({ ['OPENSKY_CLIENT_ID', 'OpenSky Client ID'], ['OPENSKY_CLIENT_SECRET', 'OpenSky Client Secret'], ['AIS_API_KEY', 'AIS Stream API Key'], + ['GFW_API_TOKEN', 'Global Fishing Watch API Token (optional)'], ].map(([key, label]) => ( {api.icon} {api.name} - - REQUIRED - + {api.required ? ( + + REQUIRED + + ) : ( + + OPTIONAL + + )} = [ + { id: 'ip', label: 'IP LOOKUP', param: 'ip', path: 'ip' }, + { id: 'dns', label: 'DNS', param: 'domain', path: 'dns' }, + { id: 'whois', label: 'WHOIS / RDAP', param: 'domain', path: 'whois' }, + { id: 'certs', label: 'CERTS', param: 'domain', path: 'certs' }, + { id: 'threats', label: 'THREATS', param: 'query', path: 'threats', optional: true }, + { id: 'bgp', label: 'BGP / ASN', param: 'query', path: 'bgp' }, + { id: 'sanctions', label: 'OFAC SDN', param: 'query', path: 'sanctions' }, + { id: 'cve', label: 'CVE', param: 'cve', path: 'cve' }, + { id: 'mac', label: 'MAC', param: 'mac', path: 'mac' }, + { id: 'github', label: 'GITHUB', param: 'username', path: 'github' }, + { id: 'leaks', label: 'LEAKS', param: 'email', path: 'leaks' }, + { id: 'sweep', label: 'IP SWEEP', param: 'ip', path: 'sweep' }, +]; + +export default function ReconPanel() { + const { t } = useTranslation(); + const [isMinimized, setIsMinimized] = useState(true); + const [activeTab, setActiveTab] = useState