"""Symmetric encryption of device credentials at rest (Fernet).""" from __future__ import annotations import base64 import hashlib from cryptography.fernet import Fernet, InvalidToken from app.config import settings def _fernet() -> Fernet: key = settings.credential_encryption_key if not key: # Derive a stable (but weak) key from SECRET_KEY so dev works without extra config. digest = hashlib.sha256(settings.secret_key.encode()).digest() key = base64.urlsafe_b64encode(digest).decode() try: return Fernet(key) except (ValueError, TypeError): # Treat provided value as raw material and derive a valid Fernet key digest = hashlib.sha256(key.encode()).digest() return Fernet(base64.urlsafe_b64encode(digest)) def encrypt_secret(plaintext: str | None) -> str | None: if not plaintext: return None return _fernet().encrypt(plaintext.encode()).decode() def decrypt_secret(token: str | None) -> str | None: if not token: return None try: return _fernet().decrypt(token.encode()).decode() except InvalidToken: return None