mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-07 18:06:49 +02:00
Fix Docker local controls and setup guidance
Allow the bundled Docker frontend proxy to reach local-operator endpoints through the private compose bridge without trusting LAN clients. This restores Time Machine, MeshChat key creation, AI pins/layers, and related local controls in Docker installs. Refresh first-run guidance so Docker users know to configure OpenSky and AIS keys through .env.
This commit is contained in:
+30
-3
@@ -13,6 +13,7 @@ import hmac
|
||||
import asyncio
|
||||
import hmac as _hmac_mod
|
||||
import hashlib as _hashlib_mod
|
||||
import ipaddress
|
||||
import json as json_mod
|
||||
import logging
|
||||
import time
|
||||
@@ -235,10 +236,36 @@ def _is_local_or_docker(host: str) -> bool:
|
||||
return host in {"127.0.0.1", "::1", "localhost"}
|
||||
|
||||
|
||||
def _docker_bridge_local_operator_enabled() -> bool:
|
||||
return str(os.environ.get("SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR", "")).strip().lower() in {
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
"on",
|
||||
}
|
||||
|
||||
|
||||
def _is_docker_bridge_host(host: str) -> bool:
|
||||
try:
|
||||
ip = ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
return False
|
||||
# Docker Desktop and the default compose bridge normally sit inside
|
||||
# 172.16.0.0/12. Keep this narrower than "any private IP" so a user who
|
||||
# intentionally binds the backend to LAN does not silently trust LAN clients.
|
||||
return ip in ipaddress.ip_network("172.16.0.0/12")
|
||||
|
||||
|
||||
def _is_trusted_local_runtime_host(host: str) -> bool:
|
||||
if _is_local_or_docker(host):
|
||||
return True
|
||||
return _docker_bridge_local_operator_enabled() and _is_docker_bridge_host(host)
|
||||
|
||||
|
||||
def require_local_operator(request: Request):
|
||||
"""Allow local tooling on loopback / Docker internal network, or a valid admin key."""
|
||||
host = (request.client.host or "").lower() if request.client else ""
|
||||
if _is_local_or_docker(host) or (_debug_mode_enabled() and host == "test"):
|
||||
if _is_trusted_local_runtime_host(host) or (_debug_mode_enabled() and host == "test"):
|
||||
return
|
||||
admin_key = _current_admin_key()
|
||||
presented = str(request.headers.get("X-Admin-Key", "") or "").strip()
|
||||
@@ -362,8 +389,8 @@ async def require_openclaw_or_local(request: Request):
|
||||
"""
|
||||
host = (request.client.host or "").lower() if request.client else ""
|
||||
|
||||
# 1. Local loopback — always allowed
|
||||
if _is_local_or_docker(host) or (_debug_mode_enabled() and host == "test"):
|
||||
# 1. Local runtime path — loopback, plus bundled Docker bridge when compose opts in
|
||||
if _is_trusted_local_runtime_host(host) or (_debug_mode_enabled() and host == "test"):
|
||||
return
|
||||
|
||||
# 2. Admin key — full trust
|
||||
|
||||
@@ -86,6 +86,18 @@ class TestRequireLocalOperator:
|
||||
def test_rfc1918_172_blocked_without_key(self):
|
||||
assert self._call_with_host("172.16.0.5") == 403
|
||||
|
||||
def test_docker_bridge_blocked_without_compose_opt_in(self):
|
||||
with patch.dict("os.environ", {"SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR": ""}):
|
||||
assert self._call_with_host("172.18.0.3") == 403
|
||||
|
||||
def test_docker_bridge_passes_with_compose_opt_in(self):
|
||||
with patch.dict("os.environ", {"SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR": "1"}):
|
||||
assert self._call_with_host("172.18.0.3") == 200
|
||||
|
||||
def test_lan_ip_still_blocked_with_compose_opt_in(self):
|
||||
with patch.dict("os.environ", {"SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR": "1"}):
|
||||
assert self._call_with_host("192.168.1.100") == 403
|
||||
|
||||
def test_rfc1918_192168_blocked_without_key(self):
|
||||
assert self._call_with_host("192.168.1.100") == 403
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ services:
|
||||
- MESH_RELAY_PEERS=${MESH_RELAY_PEERS:-}
|
||||
# Shared transport auth for operator peer push. Must be set to a unique secret per deployment.
|
||||
- MESH_PEER_PUSH_SECRET=${MESH_PEER_PUSH_SECRET:-}
|
||||
# The bundled Docker UI talks to the backend across Docker's private bridge.
|
||||
# Treat that bridge as local operator access while ports remain bound to 127.0.0.1 by default.
|
||||
- SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR=${SHADOWBROKER_TRUST_DOCKER_BRIDGE_LOCAL_OPERATOR:-1}
|
||||
volumes:
|
||||
- backend_data:/app/data
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { X, ExternalLink, Key, Shield, Radar, Globe, Satellite, Ship, Radio } from 'lucide-react';
|
||||
|
||||
const CURRENT_ONBOARDING_VERSION = '0.9.7';
|
||||
const CURRENT_ONBOARDING_VERSION = '0.9.7-docker-keys-1';
|
||||
const STORAGE_KEY = `shadowbroker_onboarding_complete_v${CURRENT_ONBOARDING_VERSION}`;
|
||||
const LEGACY_STORAGE_KEY = 'shadowbroker_onboarding_complete';
|
||||
|
||||
@@ -19,7 +19,7 @@ const API_GUIDES = [
|
||||
'Create a free account at opensky-network.org',
|
||||
'Go to Dashboard → OAuth → Create Client',
|
||||
'Copy your Client ID and Client Secret',
|
||||
'Paste both into Settings → Aviation',
|
||||
'Set OPENSKY_CLIENT_ID and OPENSKY_CLIENT_SECRET in your .env file, then restart ShadowBroker',
|
||||
],
|
||||
url: 'https://opensky-network.org/index.php?option=com_users&view=registration',
|
||||
color: 'cyan',
|
||||
@@ -33,7 +33,7 @@ const API_GUIDES = [
|
||||
'Register at aisstream.io',
|
||||
'Navigate to your API Keys page',
|
||||
'Generate a new API key',
|
||||
'Paste it into Settings → Maritime',
|
||||
'Set AIS_API_KEY in your .env file, then restart ShadowBroker',
|
||||
],
|
||||
url: 'https://aisstream.io/authenticate',
|
||||
color: 'blue',
|
||||
@@ -218,8 +218,9 @@ const OnboardingModal = React.memo(function OnboardingModal({
|
||||
</p>
|
||||
<p className="text-sm text-[var(--text-secondary)] font-mono leading-relaxed">
|
||||
OpenSky Network and AIS Stream are the free keys that make ShadowBroker
|
||||
useful immediately: live aircraft and vessel tracking. Add these first;
|
||||
trust modes and the no-key sources can come next.
|
||||
useful immediately: live aircraft and vessel tracking. For Docker installs,
|
||||
create or edit the .env file next to docker-compose.yml, then run docker
|
||||
compose up -d. For local source installs, edit backend/.env and restart.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user