diff --git a/main.py b/main.py index 045ddc4..cf4b351 100644 --- a/main.py +++ b/main.py @@ -8,6 +8,7 @@ from fastapi.templating import Jinja2Templates from starlette.middleware.sessions import SessionMiddleware import time +import urllib.parse import authentik as ak import cache @@ -56,14 +57,29 @@ def is_admin(user) -> bool: def require_admin(request: Request): user = current_user(request) + if not user and request.method == "GET" and "text/html" in request.headers.get("accept", ""): + # Ikke logget ind: login og tilbage hertil (fx et link fra en ntfy), + # i stedet for en 403-blindgyde. + nxt = request.url.path + (f"?{request.url.query}" if request.url.query else "") + raise HTTPException(303, headers={"Location": "/auth/login?next=" + urllib.parse.quote(nxt, safe="")}) + if not user: + raise HTTPException(401, "Log ind først") if not is_admin(user): raise HTTPException(403, "Kun for administratorer") return user +def _sikker_next(nxt: str | None) -> str: + # Kun stier på denne side; "//host" og "/\\host" ville sende videre ud af huset. + if nxt and nxt.startswith("/") and not nxt.startswith(("//", "/\\")): + return nxt + return "/" + + # ---------------- auth ---------------- @app.get("/auth/login") -async def login(request: Request): +async def login(request: Request, next: str = ""): + request.session["next"] = _sikker_next(next) return await oauth.authentik.authorize_redirect(request, config.REDIRECT_URI) @@ -78,7 +94,7 @@ async def callback(request: Request): "name": info.get("name") or info.get("preferred_username"), "username": info.get("preferred_username"), "email": info.get("email"), "groups": info.get("groups") or []} - return RedirectResponse("/", status_code=302) + return RedirectResponse(_sikker_next(request.session.pop("next", "/")), status_code=302) @app.get("/auth/logout") @@ -370,7 +386,7 @@ async def admin_claude_login_status(request: Request): @app.post("/admin/claude-login/start") async def admin_claude_login_start(request: Request): user = require_admin(request) - claudelogin.request((user or {}).get("preferred_username") or "?") + claudelogin.request((user or {}).get("username") or "?") return JSONResponse(claudelogin.state())