89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
import contextlib
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from fastapi import Cookie, FastAPI, Request, Response
|
|
from fastapi.responses import FileResponse, JSONResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from ..authsession import get_session
|
|
from . import ws
|
|
from .api import register_api_routes
|
|
from .reset import register_reset_routes
|
|
|
|
STATIC_DIR = Path(__file__).parent.parent / "frontend-build"
|
|
|
|
|
|
app = FastAPI()
|
|
|
|
|
|
# Global exception handlers
|
|
@app.exception_handler(ValueError)
|
|
async def value_error_handler(request: Request, exc: ValueError):
|
|
"""Handle ValueError exceptions globally with 400 status code."""
|
|
return JSONResponse(status_code=400, content={"detail": str(exc)})
|
|
|
|
|
|
@app.exception_handler(Exception)
|
|
async def general_exception_handler(request: Request, exc: Exception):
|
|
"""Handle all other exceptions globally with 500 status code."""
|
|
logging.exception("Internal Server Error")
|
|
return JSONResponse(status_code=500, content={"detail": "Internal server error"})
|
|
|
|
|
|
# Mount the WebSocket subapp
|
|
app.mount("/auth/ws", ws.app)
|
|
|
|
|
|
@app.get("/auth/forward-auth")
|
|
async def forward_authentication(request: Request, auth=Cookie(None)):
|
|
"""A validation endpoint to use with Caddy forward_auth or Nginx auth_request."""
|
|
if auth:
|
|
with contextlib.suppress(ValueError):
|
|
s = await get_session(auth)
|
|
# If authenticated, return a success response
|
|
if s.info and s.info["type"] == "authenticated":
|
|
return Response(
|
|
status_code=204,
|
|
headers={
|
|
"x-auth-user-uuid": str(s.user_uuid),
|
|
},
|
|
)
|
|
|
|
# Serve the index.html of the authentication app if not authenticated
|
|
return FileResponse(
|
|
STATIC_DIR / "index.html",
|
|
status_code=401,
|
|
headers={"www-authenticate": "PrivateToken"},
|
|
)
|
|
|
|
|
|
# Serve static files
|
|
app.mount(
|
|
"/auth/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="static assets"
|
|
)
|
|
|
|
|
|
@app.get("/auth/")
|
|
async def redirect_to_index():
|
|
"""Serve the main authentication app."""
|
|
return FileResponse(STATIC_DIR / "index.html")
|
|
|
|
|
|
@app.get("/auth/admin")
|
|
async def serve_admin():
|
|
"""Serve the admin app entry point."""
|
|
# Vite MPA builds admin as admin.html in the same outDir
|
|
admin_html = STATIC_DIR / "admin.html"
|
|
# If configured to emit admin/index.html, support that too
|
|
if not admin_html.exists():
|
|
alt = STATIC_DIR / "admin" / "index.html"
|
|
if alt.exists():
|
|
return FileResponse(alt)
|
|
return FileResponse(admin_html)
|
|
|
|
|
|
# Register API routes
|
|
register_api_routes(app)
|
|
register_reset_routes(app)
|