40 lines
1.5 KiB
Python
40 lines
1.5 KiB
Python
"""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
|