import base64 import hashlib import os from cryptography.fernet import Fernet, InvalidToken _ENCRYPTED_PREFIX = "enc:v1:" def get_session_secret() -> str: secret = os.environ.get("RADIOSYNC_SECRET_KEY") if not secret: raise RuntimeError("RADIOSYNC_SECRET_KEY must be set") return secret def _get_fernet() -> Fernet: configured_key = os.environ.get("RADIOSYNC_CONFIG_KEY") if configured_key: try: return Fernet(configured_key.encode("ascii")) except Exception as exc: raise RuntimeError("RADIOSYNC_CONFIG_KEY must be a valid Fernet key") from exc digest = hashlib.sha256(get_session_secret().encode("utf-8")).digest() return Fernet(base64.urlsafe_b64encode(digest)) def encrypt_config_value(value: str) -> str: if value is None: return None if value.startswith(_ENCRYPTED_PREFIX): return value token = _get_fernet().encrypt(value.encode("utf-8")).decode("ascii") return f"{_ENCRYPTED_PREFIX}{token}" def decrypt_config_value(value: str) -> str: if value is None or not value.startswith(_ENCRYPTED_PREFIX): return value try: token = value[len(_ENCRYPTED_PREFIX):].encode("ascii") return _get_fernet().decrypt(token).decode("utf-8") except InvalidToken as exc: raise RuntimeError("Cannot decrypt config value with the configured key") from exc