"""Verschlüsselung von Geheimnissen in der Datenbank (→ Konzept 6.2). Master-Key aus AIW_SECRET_KEY (Fernet, base64). Mehrere Keys kommagetrennt: der erste verschlüsselt, alle entschlüsseln. So lässt sich der Key wechseln, ohne alte Einträge sofort neu zu verschlüsseln. """ from cryptography.fernet import Fernet, InvalidToken, MultiFernet from app.core.errors import Invalid def generate_key() -> str: return Fernet.generate_key().decode() class Vault: def __init__(self, keys: str): parts = [k.strip() for k in keys.split(",") if k.strip()] try: self.fernet = MultiFernet([Fernet(k) for k in parts]) if parts else None except ValueError as e: raise RuntimeError("AIW_SECRET_KEY ist kein gültiger Fernet-Key (aiw gen-key).") from e @property def ready(self) -> bool: return self.fernet is not None def encrypt(self, value: str) -> str: if self.fernet is None: raise Invalid("Geheimnisse können nicht gespeichert werden: AIW_SECRET_KEY ist nicht gesetzt.") return self.fernet.encrypt(value.encode()).decode() def decrypt(self, token: str) -> str: if self.fernet is None: raise RuntimeError("AIW_SECRET_KEY ist nicht gesetzt.") try: return self.fernet.decrypt(token.encode()).decode() except InvalidToken as e: raise RuntimeError("Geheimnis lässt sich nicht entschlüsseln (falscher AIW_SECRET_KEY?).") from e