diff --git a/AGENTS.md b/AGENTS.md index 5a9f960..ad19175 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # Repository Guidelines -Current version: `1.2.3` (see `VERSIONS.md`). +Current version: `1.2.4` (see `VERSIONS.md`). ## Project Structure & Module Organization - `backend/app.py` wires FastAPI routes, MQTT lifecycle, and websocket broadcast flow. @@ -17,7 +17,7 @@ Current version: `1.2.3` (see `VERSIONS.md`). - `docker-compose.yaml` runs the service as `meshmap-live`. - `data/` stores persisted state (`state.json`), route history (`route_history.jsonl`), role overrides (`device_roles.json`), and optional neighbor overrides (`neighbor_overrides.json`). - `.env` holds dev runtime settings; `.env.example` mirrors template defaults. -- `VERSION.txt` tracks the current version (now `1.2.3`); append changes in `VERSIONS.md`. +- `VERSION.txt` tracks the current version (now `1.2.4`); append changes in `VERSIONS.md`. ## Build, Test, and Development Commands - `docker compose up -d --build` rebuilds and restarts the backend (preferred workflow). diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1f2a710..3ca9dcb 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,7 +1,7 @@ # Architecture Guide This document explains how the Mesh Live Map codebase is organized and how the components interact. -Current version: `1.2.3` (see `VERSIONS.md`). +Current version: `1.2.4` (see `VERSIONS.md`). ## High-Level Overview @@ -367,4 +367,4 @@ npx eslint backend/static/app.js ``` Versioning: -- See `VERSIONS.md` for the changelog; `VERSION.txt` mirrors the latest entry (`1.2.3`). +- See `VERSIONS.md` for the changelog; `VERSION.txt` mirrors the latest entry (`1.2.4`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c7a0ab..ccf1f76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Thanks for helping improve the MeshCore Live Map. This repo is intentionally lig 3) Verify: `curl -s http://localhost:8080/snapshot` ## Versioning -- Current version: `1.2.3` (see `VERSIONS.md`). +- Current version: `1.2.4` (see `VERSIONS.md`). - Update `VERSION.txt` when adding features. - Append a new section to `VERSIONS.md` describing the change set. diff --git a/README.md b/README.md index 7315f9c..6965ed6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Mesh Live Map -Version: `1.2.3` (see [VERSIONS.md](VERSIONS.md)) +Version: `1.2.4` (see [VERSIONS.md](VERSIONS.md)) Live MeshCore traffic map that renders nodes, routes, and activity in real time on a Leaflet map. The backend subscribes to MQTT over WebSockets+TLS or TCP, decodes MeshCore packets with `@michaelhart/meshcore-decoder`, and streams updates to the browser via WebSockets. @@ -191,6 +191,8 @@ PROD_TOKEN= Turnstile protection is also gated by `PROD_MODE=true`. If `PROD_MODE=false`, Turnstile stays off even when `TURNSTILE_ENABLED=true`. +When Turnstile is enabled, its auth cookie now grants access to `/snapshot`, `/stats`, +`/peers`, and the WebSocket without requiring a PROD token (prevents reconnect spam). Ensure `PROD_MODE`/`PROD_TOKEN` are set in `.env` (docker-compose passes them through). Generate a token: diff --git a/VERSION.txt b/VERSION.txt index 0495c4a..e8ea05d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -1.2.3 +1.2.4 diff --git a/VERSIONS.md b/VERSIONS.md index 9903bf5..3c3b92d 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -1,6 +1,7 @@ # Versions -## v1.2.3 (01-29-2026) +## v1.2.4 (01-29-2026) +- Turnstile auth now grants access to `/snapshot`, `/stats`, `/peers`, and WebSocket without requiring a PROD token (prevents WS reconnect spam). - Show Hops panel now includes total route distance (sum of hop-to-hop segments) and updates live with unit toggles. ## v1.2.2 (01-29-2026) diff --git a/backend/app.py b/backend/app.py index 34a7601..cf4aff2 100644 --- a/backend/app.py +++ b/backend/app.py @@ -575,9 +575,24 @@ def _extract_token(headers: Dict[str, str]) -> Optional[str]: return headers.get("x-access-token") or headers.get("x-token") +def _extract_cookie_token(headers: Dict[str, str], key: str) -> Optional[str]: + cookie = headers.get("cookie") + if not cookie: + return None + for part in cookie.split(";"): + part = part.strip() + if not part: + continue + if part.startswith(f"{key}="): + return part[len(key) + 1 :] + return None + + def _require_prod_token(request: Request) -> None: if not PROD_MODE: return + if TURNSTILE_ENABLED and _check_turnstile_auth(request): + return if not PROD_TOKEN: raise HTTPException(status_code=503, detail="prod_token_not_set") token = request.query_params.get("token" @@ -589,6 +604,11 @@ def _require_prod_token(request: Request) -> None: def _ws_authorized(ws: WebSocket) -> bool: + if TURNSTILE_ENABLED and turnstile_verifier: + auth_token = _extract_cookie_token(ws.headers, "meshmap_auth") or \ + _extract_token(ws.headers) + if auth_token and turnstile_verifier.verify_auth_token(auth_token): + return True if not PROD_MODE: return True if not PROD_TOKEN: diff --git a/docs.md b/docs.md index c8b1086..d691491 100644 --- a/docs.md +++ b/docs.md @@ -1,13 +1,13 @@ # Mesh Map Live: Implementation Notes This document captures the state of the project and the key changes made so far, so a new Codex session can pick up without losing context. -Current version: `1.2.3` (see `VERSIONS.md`). +Current version: `1.2.4` (see `VERSIONS.md`). ## Overview This project renders live MeshCore traffic on a Leaflet + OpenStreetMap map. A FastAPI backend subscribes to MQTT (WSS/TLS or TCP), decodes MeshCore packets using `@michaelhart/meshcore-decoder`, and broadcasts device updates and routes over WebSockets to the frontend. Core logic is split into config/state/decoder/LOS/history modules so changes are localized. The UI includes heatmap, LOS tools, map mode toggles, and a 24‑hour route history layer. ## Versioning -- `VERSION.txt` holds the current version string (`1.2.3`). +- `VERSION.txt` holds the current version string (`1.2.4`). - `VERSIONS.md` is an append-only changelog by version. ## Key Paths @@ -47,6 +47,8 @@ This project renders live MeshCore traffic on a Leaflet + OpenStreetMap map. A F `TURNSTILE_ENABLED`, `TURNSTILE_SITE_KEY`, `TURNSTILE_SECRET_KEY`, `TURNSTILE_API_URL`, and `TURNSTILE_TOKEN_TTL_SECONDS`. - `PROD_MODE`/`PROD_TOKEN` must be passed into the container (compose now forwards them). +- Turnstile auth cookie now grants access to `/snapshot`, `/stats`, `/peers`, and WS + without a PROD token, which prevents reconnect spam. - Discord/social embeds can be preserved under Turnstile with `TURNSTILE_BOT_BYPASS` and `TURNSTILE_BOT_ALLOWLIST`. diff --git a/howto.md b/howto.md index 6100437..109250e 100644 --- a/howto.md +++ b/howto.md @@ -1,7 +1,7 @@ # How-To: MQTT Broker + Live Map This guide covers two parts: stand up a MeshCore MQTT broker and point the live map at it. -Current version: `1.2.3` (see `VERSIONS.md`). +Current version: `1.2.4` (see `VERSIONS.md`). ## 1) MQTT broker (meshcore-mqtt-broker)