mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-27 01:22:27 +02:00
e36d1fc79c
External security audit by @tg12 (May 17, 2026) filed issues #201–#214 in addition to the #189–#200 batch already closed by PRs #227/#232/#260. This PR closes all eight that are real security bugs (the other six in the 201–214 range are either design discussions or upstream-abuse/TOS concerns we're keeping intentional, see issue triage notes on each). The user-facing principle for this PR: fix the security gap WITHOUT introducing a single hostile error or behavior change for legitimate users. Every fix follows the same template — fail forward, not loud. When the secure path is harder than the insecure one, build a fallback chain that ends in graceful degradation, not in a scary modal or 422 response. #205 — OpenMHZ audio redirect SSRF (services/radio_intercept.py) Replaced requests.get(..., allow_redirects=True) with a manual redirect loop that re-validates each hop's host against _OPENMHZ_AUDIO_HOSTS. Same-host redirects (CDN edge selection) still work, so legitimate audio playback is unaffected. Cross-host redirects to disallowed hosts return a generic 502 which the browser audio element handles gracefully. Cap at 5 hops. #207 — infonet/status verify_signatures DoS (routers/mesh_public.py) Silently downgrade verify_signatures=true to False for unauthenticated callers. No error surfaced — the response shape is identical, just without the O(n_events) signature verification. Authenticated callers (scoped mesh.audit) still get the full path. The frontend never passes this param so legitimate UI is unaffected. #211 — thermal/verify expensive analysis (routers/sigint.py) Added Depends(require_local_operator). Frontend has no direct callers (verified by grep); Tauri/AI agents use scoped tokens that pass the auth check. Anonymous abusers blocked silently — the legitimate UI keeps working through the Next.js admin-key proxy. #213, #214 — OpenMHZ calls/audio upstream abuse (routers/radio.py) Added Depends(require_local_operator) to both. Browser users hit these through the Next.js proxy at src/app/api/[...path]/route.ts which injects X-Admin-Key, so the auth check passes transparently. Direct attackers can no longer rotate sys_names to hammer api.openmhz.com or relay arbitrary audio streams through the backend's bandwidth. #202 — overflights unbounded hours (routers/data.py) Silently clamp `hours` to OVERFLIGHTS_MAX_HOURS (default 72, configurable). NO 422 — clients asking for an absurd window get a shorter window back with `requested_hours` and `effective_hours` hint fields. Postel's law: liberal in what we accept, conservative in what we compute. #203 — Meshtastic callsign UA leak (services/fetchers/meshtastic_map.py) Added MESHTASTIC_SEND_CALLSIGN_HEADER opt-out env var. Default is TRUE — preserves existing operator behavior (callsign sent so meshtastic.org can rate-limit per-install). Privacy-conscious operators set it to false to suppress. #206 — KiwiSDR upstream is HTTP-only (services/kiwisdr_fetcher.py) Upstream rx.linkfanel.net doesn't speak HTTPS (verified — Apache 2.4.10 only on port 80). We can't fix the transport. Instead added three layers: 1. Content validation on fetched data — reject responses with <50 receivers or >5% malformed entries (likely MITM injection). 2. Existing disk cache fallback (already present). 3. NEW: bundled static directory at backend/data/kiwisdr_directory.json shipping 798 known-good receivers. Used as last resort so the KiwiSDR map layer always renders something useful. #208 — Merkle proof DoS via /api/mesh/infonet/sync (services/mesh/mesh_hashchain.py) The endpoint is part of the cross-node federation protocol — peers legitimately call it without local-operator auth, so we can't add Depends(). Instead made the underlying operation O(1) per proof via a cached Merkle level structure on the Infonet instance: - _merkle_levels_cache + _merkle_levels_for_event_count on each Infonet instance - _invalidate_merkle_cache() called from every chain mutation point (append, ingest_events, apply_fork, cleanup_expired) - _get_merkle_levels() does the lazy recompute on first read after invalidation, then serves from cache thereafter Effect: anonymous attackers hammering the proofs endpoint hit a cached structure; the rebuild happens at most once per real chain advance. Federation untouched. #201 — Tor bundle SHA-256 bypass (services/tor_hidden_service.py) Docker users were already covered — backend/Dockerfile installs Tor via apt-get at build time (signed by Debian's package system). No runtime download needed for the 80%-of-users case. For Tauri desktop, replaced the single .sha256sum check with a multi-source verification chain implemented in _verify_tor_bundle(): 1. Try upstream .sha256sum (current behavior — fast path) 2. Try baked-in digest list at backend/data/tor_bundle_digests.json (pinned per-version, maintainer-updated) 3. If neither source is REACHABLE: HTTPS-only fallback with a loud warning (avoids breaking first-run onboarding while the maintainer hasn't yet pinned a new Tor release) A mismatch from a source that DID respond is always fatal — only the "no source reachable" case falls back to HTTPS-only. This is the "have cake and eat it" pattern: real users see no new failure modes during torproject.org outages, but MITM/compromise attacks still fail because the downloaded digest can't match what BOTH the upstream and the baked-in list report. Currently the digest file ships with placeholder values for the current Tor URLs (those URLs are already stale on torproject.org too). A follow-up commit can populate real digests when a stable Tor release is selected; until then the HTTPS-only warning fires and onboarding still works. Tests (82 total, all passing): test_openmhz_redirect_ssrf.py (5 tests) — #205 test_infonet_status_verify_gate.py (2 tests) — #207 test_overflights_clamp.py (5 tests) — #202 test_meshtastic_callsign_optout.py (3 tests) — #203 test_kiwisdr_fallback.py (6 tests) — #206 test_merkle_cache.py (6 tests) — #208 test_tor_bundle_verification.py (6 tests) — #201 test_control_surface_auth.py (extended) — #211, #213, #214 + all previous security tests (CCTV redirect, GDELT https, sentinel cache, crowdthreat opt-in, third-party fetcher gates, control surface auth) continue to pass. Pre-existing test infrastructure issue with SHARED_EXECUTOR teardown in the broader sweep exists on main too (verified) — not introduced by this PR. Credit: @tg12 reported every one of these with accurate line citations and the recommended fixes that informed this implementation. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
342 lines
18 KiB
Bash
342 lines
18 KiB
Bash
# ShadowBroker Backend — Environment Variables
|
|
# Copy this file to .env and fill in your keys:
|
|
# cp .env.example .env
|
|
|
|
# ── Required Keys ──────────────────────────────────────────────
|
|
# Without these, the corresponding data layers will be empty.
|
|
|
|
OPENSKY_CLIENT_ID= # https://opensky-network.org/ — free account, OAuth2 client ID
|
|
OPENSKY_CLIENT_SECRET= # OAuth2 client secret from your OpenSky dashboard
|
|
AIS_API_KEY= # https://aisstream.io/ — free tier WebSocket key
|
|
|
|
# ── Optional ───────────────────────────────────────────────────
|
|
|
|
# Override allowed CORS origins (comma-separated). Defaults to localhost + LAN auto-detect.
|
|
# CORS_ORIGINS=http://192.168.1.50:3000,https://my-domain.com
|
|
|
|
# Admin key — protects sensitive endpoints (API key management, system update).
|
|
# If unset, loopback/localhost requests still work for local single-host dev.
|
|
# Remote/non-loopback admin access requires ADMIN_KEY, or ALLOW_INSECURE_ADMIN=true in debug-only setups.
|
|
# Set this in production and enter the same key in Settings → Admin Key.
|
|
# ADMIN_KEY=your-secret-admin-key-here
|
|
|
|
# Allow insecure admin access without ADMIN_KEY (local dev only, beyond loopback).
|
|
# Requires MESH_DEBUG_MODE=true; do not enable this for ordinary use.
|
|
# ALLOW_INSECURE_ADMIN=false
|
|
|
|
# Default outbound User-Agent for all third-party HTTP fetchers.
|
|
# Project-generic by default — does NOT include any personal contact info or
|
|
# operator-specific identifier. Override only if you run a public relay and
|
|
# want upstreams to be able to reach you (e.g. Nominatim/OSM usage policy).
|
|
# SHADOWBROKER_USER_AGENT=ShadowBroker-OSINT/0.9 (contact: ops@example.com)
|
|
|
|
# User-Agent for Nominatim geocoding requests (per OSM usage policy).
|
|
# NOMINATIM_USER_AGENT=ShadowBroker/1.0
|
|
|
|
# ── Third-party fetcher opt-ins ────────────────────────────────
|
|
# These data sources phone home to politically/commercially sensitive
|
|
# upstreams. Disabled by default; set to "true" only if the operator
|
|
# explicitly wants the node's IP to contact these services.
|
|
#
|
|
# CrowdThreat — backend.crowdthreat.world (paid threat-intel aggregator).
|
|
# CROWDTHREAT_ENABLED=false
|
|
#
|
|
# EUvsDisinfo FIMI — euvsdisinfo.eu (EU disinformation tracker).
|
|
# FIMI_ENABLED=false
|
|
#
|
|
# Polymarket + Kalshi — US political/election prediction markets.
|
|
# PREDICTION_MARKETS_ENABLED=false
|
|
#
|
|
# Finnhub fallback / yfinance — financial market data.
|
|
# Set FINNHUB_API_KEY to enable Finnhub, or set FINANCIAL_ENABLED=true to allow
|
|
# the unauthenticated yfinance fallback to call Yahoo Finance.
|
|
# FINANCIAL_ENABLED=false
|
|
#
|
|
# NUFORC UAP sightings — huggingface.co dataset download.
|
|
# NUFORC_ENABLED=false
|
|
#
|
|
# News RSS aggregator — defaults ON. Set to "false" to disable all
|
|
# configured news feeds (kill switch for the news layer).
|
|
# NEWS_ENABLED=true
|
|
|
|
# LTA Singapore traffic cameras — leave blank to skip this data source.
|
|
# LTA_ACCOUNT_KEY=
|
|
|
|
# NASA FIRMS country-scoped fire data — enriches global CSV with conflict-zone hotspots.
|
|
# Free MAP_KEY from https://firms.modaps.eosdis.nasa.gov/map/#d:24hrs;@0.0,0.0,3.0z
|
|
# FIRMS_MAP_KEY=
|
|
|
|
# Ukraine air raid alerts from alerts.in.ua — free token from https://alerts.in.ua/
|
|
# ALERTS_IN_UA_TOKEN=
|
|
|
|
# Optional NUFORC UAP sighting map enrichment via Mapbox Tilequery.
|
|
# Leave blank to skip this optional enrichment.
|
|
# NUFORC_MAPBOX_TOKEN=
|
|
|
|
# Google Earth Engine service account for VIIRS change detection (optional).
|
|
# Download JSON key from https://console.cloud.google.com/iam-admin/serviceaccounts
|
|
# pip install earthengine-api
|
|
# GEE_SERVICE_ACCOUNT_KEY=
|
|
|
|
# ── Meshtastic MQTT Bridge ─────────────────────────────────────
|
|
# Disabled by default to respect the public Meshtastic broker.
|
|
# When enabled, subscribes to US region only. Add more regions via MESH_MQTT_EXTRA_ROOTS.
|
|
# MESH_MQTT_ENABLED=false
|
|
# MESH_MQTT_EXTRA_ROOTS=EU_868,ANZ # comma-separated additional region roots
|
|
# MESH_MQTT_INCLUDE_DEFAULT_ROOTS=true
|
|
# MESH_MQTT_BROKER=mqtt.meshtastic.org
|
|
# MESH_MQTT_PORT=1883
|
|
# Leave user/pass blank for the public Meshtastic broker default.
|
|
# MESH_MQTT_USER=
|
|
# MESH_MQTT_PASS=
|
|
|
|
# Optional Meshtastic node ID (e.g. "!abcd1234"). When set, included in the
|
|
# User-Agent sent to meshtastic.liamcottle.net so the upstream service operator
|
|
# can identify per-install traffic instead of aggregated "ShadowBroker" hits.
|
|
# Leave blank to send a generic UA. If you set MESHTASTIC_OPERATOR_CALLSIGN,
|
|
# it is included in outbound headers to meshtastic.org by default so they
|
|
# can rate-limit per-operator. Set MESHTASTIC_SEND_CALLSIGN_HEADER=false to
|
|
# suppress the callsign while still using it locally (e.g. for APRS).
|
|
# MESHTASTIC_OPERATOR_CALLSIGN=
|
|
# MESHTASTIC_SEND_CALLSIGN_HEADER=true
|
|
# MESH_MQTT_PSK= # hex-encoded, empty = default LongFast key
|
|
|
|
# ── Mesh / Reticulum (RNS) ─────────────────────────────────────
|
|
# Full-node / participant-node posture for public Infonet sync.
|
|
# MESH_NODE_MODE=participant # participant | relay | perimeter
|
|
# Legacy compatibility sunset toggles. Default posture is to block these.
|
|
# Legacy 16-hex node-id binding no longer has a boolean escape hatch; use a
|
|
# dated migration override only when you intentionally need older peers during
|
|
# migration before the hard removal target in v0.10.0 / 2026-06-01.
|
|
# MESH_BLOCK_LEGACY_NODE_ID_COMPAT=true
|
|
# MESH_ALLOW_LEGACY_NODE_ID_COMPAT_UNTIL=2026-05-15
|
|
# MESH_BLOCK_LEGACY_AGENT_ID_LOOKUP=true
|
|
# Temporary DM invite migration escape hatch. Default posture blocks importing
|
|
# legacy/compat v1/v2 DM invites; use a dated override only while retiring
|
|
# older exports and ask senders to re-export a current signed invite.
|
|
# MESH_ALLOW_COMPAT_DM_INVITE_IMPORT_UNTIL=2026-05-15
|
|
# Temporary legacy GET DM poll/count escape hatch. Default posture requires the
|
|
# signed mailbox-claim POST APIs; only use this dated override while retiring
|
|
# older clients that still call GET poll/count directly.
|
|
# MESH_ALLOW_LEGACY_DM_GET_UNTIL=2026-05-15
|
|
# Temporary raw dm1 compose/decrypt escape hatch. Default posture expects MLS
|
|
# DM bootstrap on supported peers; only use this dated override while retiring
|
|
# older clients that still need the raw dm1 helper path.
|
|
# MESH_ALLOW_LEGACY_DM1_UNTIL=2026-05-15
|
|
# Temporary legacy dm_message signature escape hatch. Default posture requires
|
|
# the full modern signed payload; only enable this with a dated migration
|
|
# override while older senders are being retired.
|
|
# MESH_ALLOW_LEGACY_DM_SIGNATURE_COMPAT_UNTIL=2026-05-15
|
|
# Rotate voter-blinding salts so new reputation events stop reusing one
|
|
# forever-stable blinded ID. Keep grace >= rotation cadence so older votes
|
|
# remain matchable while they age out of the ledger.
|
|
# MESH_VOTER_BLIND_SALT_ROTATE_DAYS=30
|
|
# MESH_VOTER_BLIND_SALT_GRACE_DAYS=30
|
|
# Deprecated legacy env vars kept only for backward config compatibility.
|
|
# Ordinary shipped gate flows keep MLS decrypt local; service-side decrypt is
|
|
# reserved for explicit recovery reads.
|
|
# MESH_GATE_BACKEND_DECRYPT_COMPAT=false
|
|
# MESH_GATE_BACKEND_DECRYPT_COMPAT_ACKNOWLEDGE=false
|
|
# Deprecated legacy env vars kept only for backward config compatibility.
|
|
# Ordinary shipped gate flows keep plaintext compose/post local and only submit
|
|
# encrypted envelopes to the backend for sign/post.
|
|
# MESH_GATE_BACKEND_PLAINTEXT_COMPAT=false
|
|
# MESH_GATE_BACKEND_PLAINTEXT_COMPAT_ACKNOWLEDGE=false
|
|
# Legacy runtime switches for recovery envelopes. Per-gate envelope_policy is
|
|
# the source of truth; leave these at the default unless testing old behavior.
|
|
# MESH_GATE_RECOVERY_ENVELOPE_ENABLE=true
|
|
# MESH_GATE_RECOVERY_ENVELOPE_ENABLE_ACKNOWLEDGE=true
|
|
# Optional operator-only recovery tradeoff. Leave off for the default posture:
|
|
# ordinary gate reads keep plaintext local/in-memory unless you explicitly use
|
|
# the recovery-envelope path.
|
|
# MESH_GATE_PLAINTEXT_PERSIST=false
|
|
# MESH_GATE_PLAINTEXT_PERSIST_ACKNOWLEDGE=false
|
|
# Legacy Phase-1 gate envelope fallback is now explicit and time-bounded per
|
|
# gate. This only controls the default expiry window when you deliberately
|
|
# re-enable that migration path for older stored envelopes.
|
|
# MESH_GATE_LEGACY_ENVELOPE_FALLBACK_MAX_DAYS=30
|
|
# Feature-flagged multiplexed gate session stream. Stream-first room ownership
|
|
# is implemented; keep off until you want that rollout enabled in your env.
|
|
# MESH_GATE_SESSION_STREAM_ENABLED=false
|
|
# MESH_GATE_SESSION_STREAM_HEARTBEAT_S=20
|
|
# MESH_GATE_SESSION_STREAM_BATCH_MS=1500
|
|
# MESH_GATE_SESSION_STREAM_MAX_GATES=16
|
|
# MESH_BOOTSTRAP_DISABLED=false
|
|
# MESH_BOOTSTRAP_MANIFEST_PATH=data/bootstrap_peers.json
|
|
# MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY=
|
|
# Infonet/Wormhole fails closed to onion/RNS by default. Only enable clearnet
|
|
# sync for local relay development or an explicitly public testnet.
|
|
# MESH_INFONET_ALLOW_CLEARNET_SYNC=false
|
|
# MESH_BOOTSTRAP_SEED_PEERS=http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000
|
|
# Add comma-separated http://*.onion peers as more private seed/relay nodes come online.
|
|
# MESH_DEFAULT_SYNC_PEERS= # legacy alias; prefer MESH_BOOTSTRAP_SEED_PEERS
|
|
# MESH_RELAY_PEERS= # comma-separated operator-trusted sync/push peers (empty by default)
|
|
# MESH_PEER_PUSH_SECRET= # REQUIRED when relay/RNS peers are configured (min 16 chars, generate with: python -c "import secrets; print(secrets.token_urlsafe(32))")
|
|
# MESH_SYNC_INTERVAL_S=300
|
|
# MESH_SYNC_FAILURE_BACKOFF_S=60
|
|
#
|
|
# Enable Reticulum bridge for Infonet event gossip.
|
|
# MESH_RNS_ENABLED=false
|
|
# MESH_RNS_APP_NAME=shadowbroker
|
|
# MESH_RNS_ASPECT=infonet
|
|
# MESH_RNS_IDENTITY_PATH=
|
|
# MESH_RNS_PEERS= # comma-separated destination hashes
|
|
# MESH_RNS_DANDELION_HOPS=2
|
|
# MESH_RNS_DANDELION_DELAY_MS=400
|
|
# MESH_RNS_CHURN_INTERVAL_S=300
|
|
# MESH_RNS_MAX_PEERS=32
|
|
# MESH_RNS_MAX_PAYLOAD=8192
|
|
# MESH_RNS_PEER_BUCKET_PREFIX=4
|
|
# MESH_RNS_MAX_PEERS_PER_BUCKET=4
|
|
# MESH_RNS_PEER_FAIL_THRESHOLD=3
|
|
# MESH_RNS_PEER_COOLDOWN_S=300
|
|
# MESH_RNS_SHARD_ENABLED=false
|
|
# MESH_RNS_SHARD_DATA_SHARDS=3
|
|
# MESH_RNS_SHARD_PARITY_SHARDS=1
|
|
# MESH_RNS_SHARD_TTL_S=30
|
|
# MESH_RNS_FEC_CODEC=xor
|
|
# MESH_RNS_BATCH_MS=200
|
|
# MESH_RNS_COVER_INTERVAL_S=0
|
|
# MESH_RNS_COVER_SIZE=64
|
|
# MESH_RNS_IBF_WINDOW=256
|
|
# MESH_RNS_IBF_TABLE_SIZE=64
|
|
# MESH_RNS_IBF_MINHASH_SIZE=16
|
|
# MESH_RNS_IBF_MINHASH_THRESHOLD=0.25
|
|
# MESH_RNS_IBF_WINDOW_JITTER=32
|
|
# MESH_RNS_IBF_INTERVAL_S=120
|
|
# MESH_RNS_IBF_SYNC_PEERS=3
|
|
# MESH_RNS_IBF_QUORUM_TIMEOUT_S=6
|
|
# MESH_RNS_IBF_MAX_REQUEST_IDS=64
|
|
# MESH_RNS_IBF_MAX_EVENTS=64
|
|
# MESH_RNS_SESSION_ROTATE_S=0
|
|
# MESH_RNS_IBF_FAIL_THRESHOLD=3
|
|
# MESH_RNS_IBF_COOLDOWN_S=120
|
|
# MESH_VERIFY_INTERVAL_S=600
|
|
# MESH_VERIFY_SIGNATURES=false
|
|
|
|
# ── Secure Storage (non-Windows) ───────────────────────────────
|
|
# Required on Linux/Docker to protect Wormhole key material at rest.
|
|
# Generate with: python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
# Also supports Docker secrets via MESH_SECURE_STORAGE_SECRET_FILE.
|
|
# MESH_SECURE_STORAGE_SECRET=
|
|
#
|
|
# To rotate the storage secret, stop the backend and run:
|
|
# 1. Dry-run first (validates without writing):
|
|
# MESH_OLD_STORAGE_SECRET=<current> MESH_NEW_STORAGE_SECRET=<new> \
|
|
# python -m scripts.rotate_secure_storage_secret --dry-run
|
|
# 2. Rotate (creates .bak backups, then rewraps envelopes):
|
|
# MESH_OLD_STORAGE_SECRET=<current> MESH_NEW_STORAGE_SECRET=<new> \
|
|
# python -m scripts.rotate_secure_storage_secret
|
|
# 3. Update MESH_SECURE_STORAGE_SECRET to the new value and restart.
|
|
#
|
|
# If rotation is interrupted, .bak files preserve the old envelopes.
|
|
# To repair corrupted secure-json payloads (not key envelopes), use:
|
|
# python -m scripts.repair_wormhole_secure_storage
|
|
|
|
# ── Mesh DM Relay ──────────────────────────────────────────────
|
|
# MESH_DM_TOKEN_PEPPER=change-me
|
|
# Keep DM relay metadata retention explicit and bounded.
|
|
# MESH_DM_KEY_TTL_DAYS=30
|
|
# MESH_DM_PREKEY_LOOKUP_ALIAS_TTL_DAYS=14
|
|
# MESH_DM_WITNESS_TTL_DAYS=14
|
|
# MESH_DM_BINDING_TTL_DAYS=3
|
|
# Optional operational bridge for externally sourced root witnesses / transparency.
|
|
# Relative paths resolve from the backend directory.
|
|
# MESH_DM_ROOT_EXTERNAL_WITNESS_IMPORT_PATH=data/root_witness_import.json
|
|
# Local single-host dev example after bootstrapping an external witness locally:
|
|
# MESH_DM_ROOT_EXTERNAL_WITNESS_IMPORT_PATH=../ops/root_witness_receipt_import.json
|
|
# Optional URI bridge for externally retrieved root witness packages.
|
|
# MESH_DM_ROOT_EXTERNAL_WITNESS_IMPORT_URI=file:///absolute/path/root_witness_import.json
|
|
# Maximum acceptable age for external witness packages before strong DM trust fails closed.
|
|
# MESH_DM_ROOT_EXTERNAL_WITNESS_MAX_AGE_S=3600
|
|
# Warning threshold for external witness packages before fail-closed max age.
|
|
# MESH_DM_ROOT_EXTERNAL_WITNESS_WARN_AGE_S=2700
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_EXPORT_PATH=data/root_transparency_ledger.json
|
|
# Local single-host dev example after publishing the transparency ledger locally:
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_EXPORT_PATH=../ops/root_transparency_ledger.json
|
|
# Optional URI used to read back and verify a published transparency ledger.
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_READBACK_URI=file:///absolute/path/root_transparency_ledger.json
|
|
# Local single-host dev readback example:
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_READBACK_URI=../ops/root_transparency_ledger.json
|
|
# Maximum acceptable age for external transparency ledgers before strong DM trust fails closed.
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_MAX_AGE_S=3600
|
|
# Warning threshold for external transparency ledgers before fail-closed max age.
|
|
# MESH_DM_ROOT_TRANSPARENCY_LEDGER_WARN_AGE_S=2700
|
|
|
|
# ── Self Update ────────────────────────────────────────────────
|
|
# MESH_UPDATE_SHA256=
|
|
|
|
# ── Wormhole (Local Agent) ─────────────────────────────────────
|
|
# WORMHOLE_HOST=127.0.0.1
|
|
# WORMHOLE_PORT=8787
|
|
# WORMHOLE_RELOAD=false
|
|
# WORMHOLE_TRANSPORT=direct
|
|
# WORMHOLE_SOCKS_PROXY=127.0.0.1:9050
|
|
# WORMHOLE_SOCKS_DNS=true
|
|
# Optional override for the loaded Rust privacy-core shared library. Leave
|
|
# unset for the default repo search order. When you override this, verify the
|
|
# authenticated wormhole status surfaces show the expected version, absolute
|
|
# library path, and SHA-256 for the loaded artifact before making stronger
|
|
# privacy claims about the deployment.
|
|
# PRIVACY_CORE_LIB=
|
|
# Minimum privacy-core version accepted when hidden/private carriers are
|
|
# enabled. Private-lane startup fails closed if the loaded artifact is
|
|
# missing, reports no parseable version, or falls below this minimum.
|
|
# PRIVACY_CORE_MIN_VERSION=0.1.0
|
|
# Comma-separated SHA-256 allowlist for the exact privacy-core artifact(s)
|
|
# your deployment is allowed to load. Required for Arti/RNS private-lane
|
|
# startup. Generate with:
|
|
# PowerShell: Get-FileHash .\privacy-core\target\release\privacy_core.dll -Algorithm SHA256
|
|
# macOS/Linux: sha256sum ./privacy-core/target/release/libprivacy_core.so
|
|
# PRIVACY_CORE_ALLOWED_SHA256=
|
|
# Optional structured release attestation artifact for the Sprint 8 release gate.
|
|
# Relative paths resolve from the backend directory. When set explicitly, a
|
|
# missing or unreadable file fails the DM relay security-suite criterion closed.
|
|
# CI/release tooling can generate this automatically via:
|
|
# uv run python scripts/release_helper.py write-attestation ...
|
|
# MESH_RELEASE_ATTESTATION_PATH=data/release_attestation.json
|
|
# Operator-only Sprint 8 release attestation. Set this only when the DM relay
|
|
# security suite has been run and passed for the current release candidate.
|
|
# File-based release attestation takes precedence when present.
|
|
# MESH_RELEASE_DM_RELAY_SECURITY_SUITE_GREEN=false
|
|
|
|
# ── OpenClaw Agent ─────────────────────────────────────────────
|
|
# HMAC shared secret for remote OpenClaw agent authentication.
|
|
# Auto-generated via the Connect OpenClaw modal — do not set manually.
|
|
# OPENCLAW_HMAC_SECRET=
|
|
# Access tier: "restricted" (read-only) or "full" (read+write+inject)
|
|
# OPENCLAW_ACCESS_TIER=restricted
|
|
|
|
# ── SAR (Synthetic Aperture Radar) Layer ───────────────────────
|
|
# Mode A — Free catalog metadata from Alaska Satellite Facility (ASF Search).
|
|
# No account, no downloads. Default-on. Set to false to disable entirely.
|
|
# MESH_SAR_CATALOG_ENABLED=true
|
|
#
|
|
# Mode B — Free pre-processed ground-change anomalies (deformation, flood,
|
|
# damage assessments) from NASA OPERA, Copernicus EGMS, GFM, EMS, UNOSAT.
|
|
# Two-step opt-in: BOTH of the following must be set together.
|
|
# 1. MESH_SAR_PRODUCTS_FETCH=allow
|
|
# 2. MESH_SAR_PRODUCTS_FETCH_ACKNOWLEDGE=true
|
|
# Either flag alone keeps Mode B disabled. You can also enable this from
|
|
# the Settings → SAR panel inside the app.
|
|
# MESH_SAR_PRODUCTS_FETCH=block
|
|
# MESH_SAR_PRODUCTS_FETCH_ACKNOWLEDGE=false
|
|
#
|
|
# NASA Earthdata Login (free, ~1 minute signup) — required for OPERA products.
|
|
# Sign up: https://urs.earthdata.nasa.gov/users/new
|
|
# Generate token: https://urs.earthdata.nasa.gov/profile → "Generate Token"
|
|
# MESH_SAR_EARTHDATA_USER=
|
|
# MESH_SAR_EARTHDATA_TOKEN=
|
|
#
|
|
# Copernicus Data Space (free, ~1 minute signup) — required for EGMS / EMS.
|
|
# Sign up: https://dataspace.copernicus.eu/
|
|
# MESH_SAR_COPERNICUS_USER=
|
|
# MESH_SAR_COPERNICUS_TOKEN=
|
|
#
|
|
# Allow OpenClaw agents to read and act on the SAR layer (default true).
|
|
# MESH_SAR_OPENCLAW_ENABLED=true
|
|
#
|
|
# Require private-tier transport (Tor / RNS) before signing and broadcasting
|
|
# SAR anomalies to the mesh. Default true — disable only for testnet/local use.
|
|
# MESH_SAR_REQUIRE_PRIVATE_TIER=true
|