Dateien
AegisSight-Monitor-Verwaltung/src/main.py
claude-dev 7c741062a9 Auth: Verwaltung auf Magic-Link umstellen (Passwort-Login entfernt)
Backend:
- src/routers/auth.py NEU: POST /api/auth/magic-link + POST /api/auth/verify
- src/auth.py: verify_password/hash_password raus, generate_magic_token rein
- src/main.py: alter Login-Endpoint + Brute-Force-Logik raus, neuer auth-Router eingebunden
- src/config.py: ALLOWED_EMAIL + PORTAL_MAGIC_LINK_* hinzu
- src/models.py: LoginRequest raus, MagicLinkRequest etc. rein
- src/email_utils/templates.py: portal_magic_link_email Template

Frontend:
- src/static/index.html: Email-Eingabe statt Passwort, Token-Verify-Logik fuer ?token= aus URL

Datenbank-Migration (migrations/2026-05-09_portal_magic_link.py):
- portal_magic_links + portal_magic_link_attempts neu
- portal_login_attempts gedroppt
- portal_admins.email Spalte hinzu, password_hash geleert

Whitelist info@aegis-sight.de, Rate-Limit 5/15 Min, Anti-Enumeration generische Antwort.
2026-05-09 02:21:40 +00:00

63 Zeilen
1.6 KiB
Python

"""Verwaltungsportal - FastAPI Anwendung.
Auth: Magic-Link (analog Monitor). Passwort-Login wurde mit Migration
2026-05-09 entfernt. Erlaubte Email-Adresse(n) sind in config.ALLOWED_EMAIL.
"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from config import STATIC_DIR, PORT
from routers import auth, organizations, licenses, users, dashboard, sources, token_usage, audit
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
)
logger = logging.getLogger("verwaltung")
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Verwaltungsportal gestartet auf Port %s", PORT)
yield
logger.info("Verwaltungsportal beendet")
app = FastAPI(
title="AegisSight Verwaltungsportal",
version="2.0.0",
lifespan=lifespan,
)
# --- Routen ---
app.include_router(auth.router)
app.include_router(organizations.router)
app.include_router(licenses.router)
app.include_router(users.router)
app.include_router(dashboard.router)
app.include_router(sources.router)
app.include_router(token_usage.router)
app.include_router(audit.router)
# --- Statische Dateien ---
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
@app.get("/")
async def index():
return FileResponse(f"{STATIC_DIR}/index.html")
@app.get("/dashboard")
async def dashboard_page():
return FileResponse(f"{STATIC_DIR}/dashboard.html")
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=PORT, reload=True)