security: harden dashboard (SSH keys, auth, uploads, CORS, non-root)
Remove SSH private keys from git, add SECRET_KEY validation, move WS auth from query string to first message, add session limits/idle timeout, PBKDF2 Fernet key, refresh token rotation, TOTP replay protection, file upload size limit + filename sanitization, symlink safety check, restrict CORS methods, IP-gate OpenClaw token, run container as non-root, rate-limit refresh/passkey endpoints, sanitize Gitea path params. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import re
|
||||
import httpx
|
||||
from fastapi import APIRouter
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from config import GITEA_URL, GITEA_TOKEN
|
||||
|
||||
router = APIRouter()
|
||||
HEADERS = {"Authorization": f"token {GITEA_TOKEN}"} if GITEA_TOKEN else {}
|
||||
_SAFE_NAME = re.compile(r'^[a-zA-Z0-9._-]+$')
|
||||
|
||||
|
||||
@router.get("/repos")
|
||||
@@ -15,6 +17,8 @@ async def list_repos():
|
||||
|
||||
@router.get("/repos/{owner}/{repo}/commits")
|
||||
async def list_commits(owner: str, repo: str, page: int = 1):
|
||||
if not _SAFE_NAME.match(owner) or not _SAFE_NAME.match(repo):
|
||||
raise HTTPException(status_code=400, detail="Invalid owner or repo name")
|
||||
async with httpx.AsyncClient() as c:
|
||||
r = await c.get(f"{GITEA_URL}/api/v1/repos/{owner}/{repo}/commits", headers=HEADERS, params={"page": page})
|
||||
return r.json()
|
||||
|
||||
Reference in New Issue
Block a user