# app/auth_core.py from contextlib import closing import bcrypt from db import get_conn # --------------------------------------------------------------------------- # DB Initialisierung: `users`-Tabelle # --------------------------------------------------------------------------- def init_auth_db(): """ Legt die users-Tabelle an. WICHTIG: password_hash wird als TEXT gespeichert, damit sowohl streamlit-authenticator als auch dein eigener bcrypt-Code kompatibel sind. """ with closing(get_conn()) as conn, conn: conn.execute( """ CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, email TEXT, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'user' ) """ ) # --------------------------------------------------------------------------- # Benutzer anlegen # --------------------------------------------------------------------------- def create_user(username: str, password: str, role: str = "user", email: str | None = None) -> bool: """ Passwort wird als bcrypt-Hash (TEXT) gespeichert. """ pw_hash = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") try: with closing(get_conn()) as conn, conn: conn.execute( "INSERT INTO users (username, email, password_hash, role) VALUES (?, ?, ?, ?)", (username, email, pw_hash, role), ) return True except Exception: return False # --------------------------------------------------------------------------- # Benutzer überprüfen (z.B. für deine alte Streamlit-Login-Maske) # --------------------------------------------------------------------------- def verify_user(username: str, password: str): """ Vergleicht eingegebenes Passwort mit dem gespeicherten bcrypt-Hash. Rückgabe: (True, role) oder (False, None) """ with closing(get_conn()) as conn: row = conn.execute( "SELECT password_hash, role FROM users WHERE username = ?", (username,), ).fetchone() if not row: return False, None stored_hash, role = row # stored_hash ist TEXT → zurück nach bytes ok = bcrypt.checkpw(password.encode("utf-8"), stored_hash.encode("utf-8")) return (ok, role) if ok else (False, None) # --------------------------------------------------------------------------- # Rolle für einen Benutzer holen (für Streamlit-Inhalte) # --------------------------------------------------------------------------- def get_role_for_user(username: str) -> str: with closing(get_conn()) as conn: row = conn.execute( "SELECT role FROM users WHERE username = ?", (username,), ).fetchone() return row[0] if row else "user" # --------------------------------------------------------------------------- # Credential-Lader für streamlit-authenticator # --------------------------------------------------------------------------- def load_credentials_from_db() -> dict: """ Baut das credentials-Dict so: { "usernames": { "hansi": { "email": "hansi@example.com", "name": "hansi", "password": "$2b$12$...", }, ... } } streamlit-authenticator prüft dann Login + Cookies automatisch. """ creds = {"usernames": {}} with closing(get_conn()) as conn: rows = conn.execute( "SELECT username, email, password_hash FROM users" ).fetchall() for username, email, pw_hash in rows: # pw_hash kommt als TEXT creds["usernames"][username] = { "name": username, "email": email or f"{username}@example.local", "password": pw_hash, # TEXT → streamlit-authenticator-kompatibel } return creds