47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
import base64
|
|
import hashlib
|
|
from cryptography.fernet import Fernet
|
|
from flask import current_app
|
|
|
|
class CryptoService:
|
|
"""
|
|
Servicio de cifrado simétrico seguro para contraseñas y tokens sensibles
|
|
almacenados en la base de datos (credenciales SMTP, Client Secrets, Moodle Tokens).
|
|
"""
|
|
|
|
@staticmethod
|
|
def _get_fernet() -> Fernet:
|
|
# Derivar clave válida para Fernet (32 bytes urlsafe base64) desde SECRET_KEY
|
|
try:
|
|
secret = current_app.config.get('SECRET_KEY', 'default-unicaba-edu-space-secret-key-32b!')
|
|
except RuntimeError:
|
|
secret = 'default-unicaba-edu-space-secret-key-32b!'
|
|
|
|
# Hash SHA-256 para obtener 32 bytes y codificar en base64 seguro para URL
|
|
key = base64.urlsafe_b64encode(hashlib.sha256(secret.encode('utf-8')).digest())
|
|
return Fernet(key)
|
|
|
|
@classmethod
|
|
def encrypt(cls, plain_text: str) -> str:
|
|
"""Cifra un texto plano y retorna el string cifrado."""
|
|
if not plain_text:
|
|
return ''
|
|
fernet = cls._get_fernet()
|
|
encrypted_bytes = fernet.encrypt(plain_text.encode('utf-8'))
|
|
return encrypted_bytes.decode('utf-8')
|
|
|
|
@classmethod
|
|
def decrypt(cls, cipher_text: str) -> str:
|
|
"""Descifra un texto cifrado y retorna el texto original. Si falla, retorna vacío."""
|
|
if not cipher_text:
|
|
return ''
|
|
try:
|
|
fernet = cls._get_fernet()
|
|
decrypted_bytes = fernet.decrypt(cipher_text.encode('utf-8'))
|
|
return decrypted_bytes.decode('utf-8')
|
|
except Exception:
|
|
# Si no era un texto cifrado con Fernet o fue alterado, retornar el texto tal cual o vacío
|
|
return cipher_text
|
|
|
|
crypto_service = CryptoService()
|