"""Anlegen des ersten Administratorkontos beim Start. Bewusst eng gefasst: Das Konto entsteht nur, wenn die Datenbank noch *gar keinen* Nutzer enthält. Damit kann ein vergessener Eintrag in der .env kein bestehendes Konto überschreiben und auch kein zweites Admin-Konto nachschieben. Das angelegte Konto trägt `must_change_password`. Bis zum Wechsel sind alle Routen gesperrt, die an `verified_user` hängen - also alles außer "eigenes Profil lesen" und "Passwort ändern". Der Wert in der .env ist nach der ersten Anmeldung damit wertlos. """ import logging from sqlalchemy import func, select from sqlalchemy.orm import Session from app.config import settings from app.models import User from app.security import hash_password, normalize_email, utcnow log = logging.getLogger(__name__) MIN_LENGTH = 12 def ensure_initial_admin(db: Session) -> None: password = settings.initial_admin_password user_count = db.scalar(select(func.count()).select_from(User)) or 0 email = normalize_email(settings.admin_email) if user_count > 0: if password: log.warning( "ADMIN_INITIAL_PASSWORD ist gesetzt, es existieren aber bereits " "%d Konten - der Wert wird ignoriert. Entferne ihn aus der .env, " "damit kein Passwort unnötig in der Umgebung steht.", user_count, ) return if not password: log.info( "Keine Konten vorhanden und kein ADMIN_INITIAL_PASSWORD gesetzt. " "Erstes Konto über POST /api/auth/register anlegen (%s wird dabei " "automatisch Administrator).", email, ) return if len(password) < MIN_LENGTH: raise RuntimeError( f"ADMIN_INITIAL_PASSWORD ist zu kurz (mindestens {MIN_LENGTH} Zeichen)." ) admin = User( email=email, display_name="Administrator", password_hash=hash_password(password), # Die Adresse gilt als bestätigt: Wer die .env schreiben kann, # hat ohnehin vollen Zugriff. Ein Verifikationsumweg brächte hier # keinen Sicherheitsgewinn, nur eine Abhängigkeit vom Mailversand # bei der Ersteinrichtung. verified_at=utcnow(), is_admin=True, must_change_password=True, ) db.add(admin) db.flush() log.warning( "Administratorkonto %s aus ADMIN_INITIAL_PASSWORD angelegt. " "Das Passwort MUSS bei der ersten Anmeldung geändert werden; bis dahin " "sind alle übrigen Funktionen gesperrt. Danach den Wert aus der .env " "entfernen.", email, )