diff --git a/backend/main.py b/backend/main.py index 179134e..09133a5 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1073,10 +1073,20 @@ def require_admin(request: Request): raise HTTPException(status_code=403, detail=detail) +def _is_local_or_docker(host: str) -> bool: + """Return True if the IP is loopback or a Docker-internal private network.""" + if host in {"127.0.0.1", "::1", "localhost"}: + return True + # Docker bridge networks use 172.x.x.x or 192.168.x.x ranges + if host.startswith("172.") or host.startswith("192.168.") or host.startswith("10."): + return True + return False + + def require_local_operator(request: Request): - """Allow local tooling on loopback, or a valid admin key from elsewhere.""" + """Allow local tooling on loopback / Docker internal network, or a valid admin key.""" host = (request.client.host or "").lower() if request.client else "" - if host in {"127.0.0.1", "::1", "localhost"} or (_debug_mode_enabled() and host == "test"): + if _is_local_or_docker(host) or (_debug_mode_enabled() and host == "test"): return admin_key = _current_admin_key() presented = str(request.headers.get("X-Admin-Key", "") or "").strip() diff --git a/frontend/src/components/ChangelogModal.tsx b/frontend/src/components/ChangelogModal.tsx index 23bb71e..77eebea 100644 --- a/frontend/src/components/ChangelogModal.tsx +++ b/frontend/src/components/ChangelogModal.tsx @@ -20,7 +20,7 @@ const STORAGE_KEY = `shadowbroker_changelog_v${CURRENT_VERSION}`; const RELEASE_TITLE = 'InfoNet Experimental Testnet — Decentralized Intelligence Experiment'; const HEADLINE_FEATURE = { - icon: , + icon: , title: 'InfoNet Experimental Testnet is Live', subtitle: 'The first decentralized intelligence mesh built directly into an OSINT platform. This is an experimental testnet — NOT a privacy tool.', details: [ @@ -34,43 +34,43 @@ const HEADLINE_FEATURE = { const NEW_FEATURES = [ { - icon: , + icon: , title: 'Meshtastic + APRS Radio Integration', desc: 'Live Meshtastic mesh radio nodes plotted worldwide via MQTT. APRS amateur radio positioning via APRS-IS TCP feed. Both integrated into Mesh Chat and the SIGINT grid. Note: Mesh radio is NOT private — RF transmissions are public by nature.', color: 'amber', }, { - icon: , + icon: , title: 'Mesh Terminal', desc: 'Built-in command-line interface. Send messages, DMs, run market commands, inspect gate state. Draggable panel, minimizes to the top bar. Type "help" to see everything.', color: 'cyan', }, { - icon: , + icon: , title: 'Shodan Device Search', desc: 'Query Shodan directly from ShadowBroker. Search internet-connected devices by keyword, CVE, or port — results plotted as a live overlay on the map with configurable marker style.', color: 'green', }, { - icon: , + icon: , title: 'CCTV Mesh Expanded — 12 Sources, 11,000+ Cameras', desc: 'Massive expansion: added Spain (DGT national + Madrid city), California (12 Caltrans districts), Washington State, Georgia, Illinois, Michigan, and Windy Webcams. Now covers 6 countries. Enabled by default.', color: 'emerald', }, { - icon: , + icon: , title: 'Train Tracking (Amtrak + European Rail)', desc: 'Real-time Amtrak train positions across the US and European rail via DigiTraffic. Speed, heading, route, and status for every train on the network.', color: 'blue', }, { - icon: , + icon: , title: '8 New Intelligence Layers', desc: 'Volcanoes (Smithsonian), air quality PM2.5 (OpenAQ), severe weather alerts, fishing activity (Global Fishing Watch), military bases, 35K+ power plants, SatNOGS ground stations, TinyGS LoRa satellites, VIIRS nightlights.', color: 'purple', }, { - icon: , + icon: , title: 'Sentinel Hub Imagery + Desktop Shell Scaffold', desc: 'Copernicus CDSE satellite imagery via Sentinel Hub Process API with OAuth2 token flow. Desktop-native control routing scaffold (pre-Tauri) with session profiles and audit trail.', color: 'yellow', @@ -206,7 +206,7 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog className="fixed inset-0 z-[10001] flex items-center justify-center pointer-events-none" >
e.stopPropagation()} > {/* Header */} @@ -214,14 +214,14 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog
-
+
v{CURRENT_VERSION}
-

+

WHAT'S NEW

-

+

{RELEASE_TITLE.toUpperCase()}

@@ -239,14 +239,14 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* === HEADLINE: InfoNet Testnet === */}
-
+
{HEADLINE_FEATURE.icon}
-
+
{HEADLINE_FEATURE.title}
-
+
{HEADLINE_FEATURE.subtitle}
@@ -256,7 +256,7 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {HEADLINE_FEATURE.details.map((para, i) => (

{para}

@@ -265,12 +265,12 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* Testnet disclaimer */}
- !! + !!
- + EXPERIMENTAL TESTNET — NO PRIVACY GUARANTEE - + InfoNet messages are obfuscated but NOT encrypted end-to-end. The Mesh network (Meshtastic/APRS) is NOT private — radio transmissions are inherently public. Do not send anything sensitive on any channel. Privacy and E2E encryption @@ -281,7 +281,7 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* CTA */}
- + {HEADLINE_FEATURE.callToAction}
@@ -289,8 +289,8 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* === Other New Features === */}
-
-
+
+
NEW CAPABILITIES
@@ -301,10 +301,10 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog >
{f.icon}
-
+
{f.title}
-
+
{f.desc}
@@ -315,15 +315,15 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* Bug Fixes */}
-
- +
+ FIXES & IMPROVEMENTS
{BUG_FIXES.map((fix, i) => (
- + - + + + {fix}
@@ -333,8 +333,8 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog {/* Contributors */}
-
- +
+ COMMUNITY CONTRIBUTORS
@@ -343,19 +343,19 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog key={i} className="flex items-start gap-2 px-3 py-2 border border-pink-500/20 bg-pink-500/5" > - +
- + {c.name} - + {' '} — {c.desc} {c.pr && ( - + {' '} (PR {c.pr}) @@ -371,7 +371,7 @@ const ChangelogModal = React.memo(function ChangelogModal({ onClose }: Changelog