feat(dashboard): login-ul cu token, dezactivat implicit

Accesul la /echo trece deja prin `tailscale serve` (tailnet only), deci
formularul de token era o a doua autentificare peste una existentă.

`DASHBOARD_AUTH` nesetat => `_check_dashboard_cookie` trece mereu: paginile
.html nu mai redirectează la /echo/login, POST-urile /api/* nu mai dau 401,
iar /echo/login sare direct la destinație. Codul de login rămâne intact —
`DASHBOARD_AUTH=on` în dashboard/.env îl reactivează neschimbat.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188YmDTUAzVvZDVh8JL8xSa
This commit is contained in:
2026-08-31 22:11:39 +00:00
parent a62e4d4ab7
commit 2d8ee9b581
2 changed files with 33 additions and 3 deletions

View File

@@ -7,6 +7,11 @@ This mixin provides:
- _check_dashboard_cookie — used by the global POST middleware (and the
SSE GET endpoint) to gate access.
Authentication is **disabled by default** — the dashboard is only reachable
over the Tailscale tailnet, which already authenticates the caller, so the
extra token prompt added nothing. Set `DASHBOARD_AUTH=on` in `dashboard/.env`
to re-enable the token login (everything below still works unchanged).
`DASHBOARD_TOKEN` is read once from `dashboard/.env` (loaded into
`os.environ` by `dashboard/constants.py` at import time). When the token is
not configured we generate a random one at startup, stash it in-process,
@@ -34,6 +39,17 @@ _COOKIE_PATH = "/echo/"
_DASHBOARD_TOKEN: str | None = None
def _auth_enabled() -> bool:
"""True only when `DASHBOARD_AUTH` is explicitly turned on.
Off by default: access control is delegated to Tailscale. When off,
`_check_dashboard_cookie` always passes and `/echo/login` is never shown.
"""
return os.environ.get("DASHBOARD_AUTH", "").strip().lower() in {
"on", "1", "true", "yes",
}
def _get_dashboard_token() -> str:
"""Return the dashboard token (cached). Generates a random one if absent.
@@ -79,7 +95,12 @@ class AuthHandlers:
# ── helpers ────────────────────────────────────────────────────────
def _check_dashboard_cookie(self) -> bool:
"""Return True if the request carries a valid `dashboard` cookie."""
"""Return True if the request carries a valid `dashboard` cookie.
Always True when auth is disabled (the default) — see `_auth_enabled`.
"""
if not _auth_enabled():
return True
raw = self.headers.get("Cookie", "") or ""
cookies = _parse_cookie_header(raw)
provided = cookies.get(_COOKIE_NAME, "")
@@ -114,6 +135,15 @@ class AuthHandlers:
SameSite=Strict; Path=/echo/ so it scopes to the dashboard reverse
proxy mount.
"""
if not _auth_enabled():
# Nothing to log into — bounce straight to the dashboard.
self.send_response(302)
self.send_header("Location", "/echo/workspace.html")
self.send_header("Content-Length", "0")
self.send_header("Cache-Control", "no-store")
self.end_headers()
return
# Accept JSON body too (login.html might POST JSON in Lane B2)
ctype = (self.headers.get("Content-Type", "") or "").lower()
if "application/json" in ctype: