import os from fastapi import APIRouter, Request from fastapi.responses import RedirectResponse from fastapi.templating import Jinja2Templates from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError templates = Jinja2Templates(directory="templates") router = APIRouter() OWNER_PASSWORD_HASH = os.getenv("OWNER_PASSWORD_HASH", "") ph = PasswordHasher() @router.get("/login") async def login_form(request: Request): if request.session.get("authenticated"): return RedirectResponse("/", status_code=303) return templates.TemplateResponse(request=request, name="login.html", context={"request": request}) @router.post("/login") async def login(request: Request): if request.session.get("authenticated"): return RedirectResponse("/", status_code=303) form = await request.form() password = form.get("password", "") if not OWNER_PASSWORD_HASH: error = "Server not configured: OWNER_PASSWORD_HASH not set" return templates.TemplateResponse( request=request, name="login.html", context={"request": request, "error": error}, status_code=500 ) try: ph.verify(OWNER_PASSWORD_HASH, password) request.session["authenticated"] = True return RedirectResponse("/", status_code=303) except VerifyMismatchError: pass return templates.TemplateResponse( request=request, name="login.html", context={"request": request, "error": "Invalid password"}, status_code=401 ) @router.post("/logout") async def logout(request: Request): request.session.clear() return RedirectResponse("/login", status_code=303)