Major changes to server startup. Admin page tuning.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import Cookie, FastAPI, Request, Response
|
||||
@@ -14,7 +16,41 @@ from .reset import register_reset_routes
|
||||
STATIC_DIR = Path(__file__).parent.parent / "frontend-build"
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI): # pragma: no cover - startup path
|
||||
"""Application lifespan to ensure globals (DB, passkey) are initialized in each process.
|
||||
|
||||
We populate configuration from environment variables (set by the CLI entrypoint)
|
||||
so that uvicorn reload / multiprocess workers inherit the settings.
|
||||
"""
|
||||
from .. import globals
|
||||
|
||||
rp_id = os.getenv("PASSKEY_RP_ID", "localhost")
|
||||
rp_name = os.getenv("PASSKEY_RP_NAME") or None
|
||||
origin = os.getenv("PASSKEY_ORIGIN") or None
|
||||
default_admin = (
|
||||
os.getenv("PASSKEY_DEFAULT_ADMIN") or None
|
||||
) # still passed for context
|
||||
default_org = os.getenv("PASSKEY_DEFAULT_ORG") or None
|
||||
try:
|
||||
# CLI (__main__) performs bootstrap once; here we skip to avoid duplicate work
|
||||
await globals.init(
|
||||
rp_id=rp_id,
|
||||
rp_name=rp_name,
|
||||
origin=origin,
|
||||
default_admin=default_admin,
|
||||
default_org=default_org,
|
||||
bootstrap=False,
|
||||
)
|
||||
except ValueError as e:
|
||||
logging.error(f"⚠️ {e}")
|
||||
# Re-raise to fail fast
|
||||
raise
|
||||
yield
|
||||
# (Optional) add shutdown cleanup here later
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
|
||||
# Global exception handlers
|
||||
@@ -71,16 +107,24 @@ async def redirect_to_index():
|
||||
|
||||
|
||||
@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)
|
||||
async def serve_admin(auth=Cookie(None)):
|
||||
"""Serve the admin app entry point if an authenticated session exists.
|
||||
|
||||
If no valid authenticated session cookie is present, return a 401 with the
|
||||
main app's index.html so the frontend can initiate login/registration flow.
|
||||
"""
|
||||
if auth:
|
||||
with contextlib.suppress(ValueError):
|
||||
s = await get_session(auth)
|
||||
if s.info and s.info.get("type") == "authenticated":
|
||||
return FileResponse(STATIC_DIR / "admin" / "index.html")
|
||||
|
||||
# Not authenticated: serve main index with 401
|
||||
return FileResponse(
|
||||
STATIC_DIR / "index.html",
|
||||
status_code=401,
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
|
||||
# Register API routes
|
||||
|
||||
Reference in New Issue
Block a user