79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
"""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,
|
|
)
|