fix: harden dashboard RBAC and cookie auth flows
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 2m17s

Restrict Docker/Files writes to admins, move terminal websocket auth to cookie-first with temporary query fallback, and migrate refresh-token handling to httpOnly cookies for safer session persistence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Gan, Jimmy
2026-03-09 23:44:23 +08:00
parent e72665c466
commit 4201917e17
11 changed files with 185 additions and 115 deletions
+4 -4
View File
@@ -9,7 +9,7 @@ from slowapi.errors import RateLimitExceeded
from routers import docker_router, gitea, files, terminal, system, auth, chat_summary, security, passkey, totp, litellm, cc_connect, info_engine
import auth as auth_module
import config
from rbac import require_page, require_write
from rbac import require_page
import asyncio
import httpx
@@ -160,11 +160,11 @@ app.include_router(totp.router, prefix="/api/auth", tags=["totp"])
# Protected endpoints with page-level RBAC
app.include_router(docker_router.router, prefix="/api/docker",
dependencies=[Depends(_inject_user), Depends(require_page("docker")), Depends(require_write())])
dependencies=[Depends(_inject_user), Depends(require_page("docker"))])
app.include_router(gitea.router, prefix="/api/gitea",
dependencies=[Depends(_inject_user), Depends(require_page("gitea"))])
app.include_router(files.router, prefix="/api/files",
dependencies=[Depends(_inject_user), Depends(require_page("files")), Depends(require_write())])
dependencies=[Depends(_inject_user), Depends(require_page("files"))])
app.include_router(system.router, prefix="/api/system",
dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))])
app.include_router(litellm.router, prefix="/api/litellm",
@@ -178,7 +178,7 @@ app.include_router(info_engine.router, prefix="/api/info-engine",
app.include_router(security.router, prefix="/api/security",
dependencies=[Depends(_inject_user), Depends(require_page("security"))])
# WebSocket endpoint (auth handled inside handler via Query param)
# WebSocket endpoint (auth handled inside handler via auth cookie; query token fallback temporary)
app.add_api_websocket_route("/ws/terminal", terminal.ws_endpoint)
app.mount("/", StaticFiles(directory="/app/static", html=True), name="static")