Ctrl K
ComunidadGuías…

crypto_secrets.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""crypto_secrets.py - at-rest encryption for user-supplied credentials
(CloudLog API keys, QRZ.com/HamQTH.com passwords) stored in users.json.

Key derivation: SHA-256 of this installation's JWT_SECRET (config.SECRET,
a random value already generated per-install into .env by config.ensure_env),
base64-urlsafe encoded for Fernet. Reuses the existing per-installation
secret instead of introducing a second key file to manage/lose/back up.
"""
import base64
import hashlib

try:
    from cryptography.fernet import Fernet, InvalidToken
    HAS_CRYPTO = True
except ImportError:
    HAS_CRYPTO = False

PREFIX = "enc1:"

_fernet = None


def _get_fernet():
    global _fernet
    if _fernet is None:
        from config import SECRET
        key = base64.urlsafe_b64encode(hashlib.sha256(SECRET.encode()).digest())
        _fernet = Fernet(key)
    return _fernet


def encrypt_secret(value: str) -> str:
    """Encrypt a credential for storage. Empty values, and values already
    starting with PREFIX, pass through unchanged. If the cryptography
    package is unavailable, degrades to plaintext (same behavior as before
    this module existed) rather than failing the save."""
    if not value or value.startswith(PREFIX) or not HAS_CRYPTO:
        return value
    return PREFIX + _get_fernet().encrypt(value.encode()).decode()


def decrypt_secret(value: str) -> str:
    """Decrypt a stored credential. Values without the PREFIX are treated
    as legacy plaintext (pre-encryption installs, or crypto unavailable)
    and returned as-is - they get encrypted the next time they're saved."""
    if not value or not value.startswith(PREFIX) or not HAS_CRYPTO:
        return value
    try:
        return _get_fernet().decrypt(value[len(PREFIX):].encode()).decode()
    except InvalidToken:
        return value