add admin stuff

This commit is contained in:
2026-08-20 10:43:19 +02:00
parent 7108d446d8
commit 91758a2701
19 changed files with 2514 additions and 85 deletions

View File

@ -7,13 +7,14 @@ from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi import Depends, FastAPI, Request
from fastapi.openapi.utils import get_openapi
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.admin.routes import router as admin_router
from app.auth.deps import get_current_user
from app.auth.deps import CurrentUser, require_global_admin
from app.auth.routes import router as auth_router
from app.catalog.routes import router as catalog_router
from app.db import close_db, init_db
@ -84,6 +85,15 @@ async def dashboard(request: Request):
return templates.TemplateResponse(request, "dashboard.html", {})
@app.get("/admin", response_class=HTMLResponse)
async def admin_page(request: Request):
# Wie /dashboard: Seite selbst ist statisches Markup ohne Secrets, die
# Admin-Pruefung (is_admin) erfolgt clientseitig ueber GET /auth/me
# (Redirect zu /dashboard falls kein Admin) UND serverseitig hart auf
# jedem einzelnen /admin/*-API-Aufruf (require_admin_or_scope).
return templates.TemplateResponse(request, "admin.html", {})
@app.get("/terminal/{host_id}", response_class=HTMLResponse)
async def terminal_page(request: Request, host_id: int):
return templates.TemplateResponse(request, "terminal.html", {"host_id": host_id})
@ -97,3 +107,24 @@ async def rdp_page(request: Request, host_id: int):
@app.get("/healthz")
async def healthz():
return {"status": "ok"}
# --- API-Dokumentation --------------------------------------------------------
#
# docs_url/redoc_url/openapi_url sind am FastAPI()-Konstruktor bewusst
# deaktiviert (siehe oben) -- eine oeffentlich erreichbare API-Uebersicht
# waere auf einem oeffentlich exponierten Jumphost unnoetige Informations-
# preisgabe (Konzept 6.6). Stattdessen: eigene, auf eingeloggte Admins
# beschraenkte Routen. Bewusst KEIN vendored/CDN-bezogenes Swagger-UI-Bundle
# (Konzept 4.1/6.6: kein Laufzeit-CDN-Bezug im Browser) -- stattdessen eine
# schlanke selbstgebaute Ansicht (templates/api_docs.html +
# static/js/api-docs.js), die /openapi.json clientseitig ausliest.
@app.get("/openapi.json", include_in_schema=False)
async def protected_openapi_schema(admin: CurrentUser = Depends(require_global_admin)):
return get_openapi(title=app.title, version=app.version, routes=app.routes)
@app.get("/docs", response_class=HTMLResponse, include_in_schema=False)
async def protected_api_docs(request: Request, admin: CurrentUser = Depends(require_global_admin)):
return templates.TemplateResponse(request, "api_docs.html", {})