Skip to main content

Freedec: Sistema de Entrega y Canje Desatendido de Documentos Confidenciales

Python Django DRF Version Security Zeroization OWASP License: GPL v3

🇪🇸 Leer en Español (Guía Completa)   |   🇬🇧 Read in English (Full Guide)


🇪🇸 Español: Guía de Freedec

Bienvenido a la documentación de Freedec, una aplicación Django diseñada para la entrega y canje desatendido de documentos confidenciales con datos personales, basada en el cotejo unívoco del Hash SHA-256 del archivo y verificación en tiempo real por OTP (One-Time Password).


🛡️ Principios de Diseño y Reglas de Oro

  1. CERO TRANSPORTE DEL BINARIO POR EL CLIENTE: El usuario final NUNCA sube el archivo .enc para identificarse o solicitar acceso. El localizador oficial y prueba de trámite es exclusivamente el hash SHA-256 del archivo original (cadena hexadecimal de 64 caracteres).
  2. SIN CONTRASEÑAS HUMANAS (Zero Human-Readable Passwords): Ningún usuario ni administrador visualiza, ingresa o gestiona contraseñas en texto claro. El descifrado es 100% interno y desatendido por el propio código del backend en memoria RAM tras validar el OTP.
  3. BURN-AFTER-READ CON DESTRUCCIÓN SEGURA (Zeroization/Shredding O(1) RAM): Al primer canje exitoso por un usuario autorizado, el archivo cifrado en disco se sobrescribe con bytes criptográficamente aleatorios en bloques de 64 KB (os.urandom(CHUNK_SIZE)), forzando la sincronización en disco físico con flush() y os.fsync() antes de desvincularlo del sistema de archivos (os.remove()), y el registro pasa a estado consumido.

📑 Índice de Contenidos

  1. Flujo Criptográfico y Operativo
  2. Entorno de Pruebas y Sandbox de Staging
  3. Uso de la Interfaz Web (Web GUI)
  4. Gestión en Django Admin
  5. Endpoints de la API REST
  6. Comandos de Gestión CLI
  7. Configuración de Seguridad en settings.py

1. Flujo Criptográfico y Operativo

Alta del Documento (Admin):

  1. El administrador sube el documento original (PDF, LibreOffice u Office) y especifica la lista de correos autorizados.
  2. El sistema valida las cabeceras binarias (Magic Bytes) y calcula el hash SHA-256 mediante lectura en bloques de 64 KB (anti-DoS/OOM).
  3. Genera una Clave Maestra de Datos (DEK) única con Fernet.generate_key().
  4. Cifra el contenido del archivo con la DEK y lo guarda en disco como .enc.
  5. Cifra la DEK internamente con la clave maestra del servidor settings.FREEDEC_FERNET_KEY y la almacena en encrypted_dek.
  6. El administrador entrega el Hash SHA-256 al usuario como prueba y localizador oficial.

Solicitud de Acceso:

  1. El usuario final accede a /freedec/solicitar/ e introduce el Hash SHA-256 y su correo electrónico (o mediante enlace con ?hash=...).
  2. Si el hash no existe o el correo no está autorizado, el backend ejecuta un cálculo simulado PBKDF2 para neutralizar ataques de temporización (Timing Attacks) y devuelve una respuesta neutra preventiva.
  3. Si el documento ya fue consumido (is_consumed == True), envía un correo formal al solicitante notificando quién y cuándo lo retiró (consumed_by, consumed_at), registrando intento_post_consumo en la auditoría.
  4. Si está activo y autorizado, genera un código OTP numérico de 6 dígitos (secrets.choice), fija caducidad estricta a 15 minutos, envía el código por correo con enlace a /freedec/canjear/ y audita otp_enviado.

Canje y Destrucción Física (Burn-After-Read):

  1. El usuario introduce el código OTP en /freedec/canjear/.
  2. Se valida el código mediante comparación en tiempo constante (secrets.compare_digest). Si falla 3 veces, el token se bloquea definitivamente (otp_invalido_bloqueado).
  3. Al validar el OTP, el backend descifra la DEK en RAM usando FREEDEC_FERNET_KEY, descifra los bytes del archivo original en memoria, ejecuta la sobrescritura física con bytes aleatorios (os.urandom) y borrado en disco, marca el documento como consumido y devuelve inmediatamente un FileResponse con el archivo original en memoria.

2. Entorno de Pruebas y Sandbox de Staging (100% Desatendido)

Freedec incluye un comando de arranque integral para montar un entorno de pruebas completo en segundos sin intervención manual:

Inicialización Rápida

# 1. Clonar e instalar dependencias con Poetry
git clone https://github.com/jrubioh1/Freedec.git
cd Freedec
poetry install

# 2. Inicializar el sandbox de staging de forma 100% desatendida
poetry run python manage.py setup_staging --clean

El comando setup_staging realiza automáticamente:

  • Genera el archivo de configuración freedec.ini desde freedec.ini.template si no existe.
  • Aplica todas las migraciones de base de datos desde cero.
  • Crea el Administrador Maestro (admin / admin123).
  • Importa la malla de Unidades Organizativas (UO) (DIRECCION, RRHH, LEGAL, AUDITORIA) y usuarios departamentales con contraseñas predefinidas.
  • Genera y cifra documentos confidenciales de prueba con distintas políticas (FIRST_ACCESS y ALL_RECIPIENTS).
  • Imprime un panel resumen en consola con todas las URLs de acceso, credenciales, hashes SHA-256 y enlaces de 1-clic directos.

Iniciar el Servidor de Pruebas

poetry run python manage.py runserver 8000

Ejecutar Suite de Pruebas Automatizadas (Pytest)

poetry run pytest -v

Demostración Interactiva del Flujo

poetry run python scripts/demo_flow.py

3. Uso de la Interfaz Web (Web GUI)

  • Solicitar Acceso (/freedec/solicitar/):
    • Formulario limpio con dos campos: Hash SHA-256 y Correo Electrónico.
    • Soporta parámetro URL directo: /freedec/solicitar/?hash=<SHA256>.
    • Redirige a la vista de canje guardando los datos en sesión.
  • Canjear OTP (/freedec/canjear/):
    • Entrada del código OTP numérico de 6 dígitos.
    • Entrega inmediata del archivo original vía descarga de navegador (FileResponse).
    • Destrucción simultánea del archivo cifrado en disco.

4. Gestión en Django Admin

  • Panel EncryptedDocumentAdmin:

    • Columnas: original_filename, file_hash, burn_policy, consumption_status_badge, expiry_status_badge, audit_download_button, corporate_email_button, terminate_action_button.
    • Cero contraseñas: Ningún campo muestra ni almacena contraseñas humanas.
    • Descripción editable del documento: Campo editable con valor corporativo por defecto, modificable tanto en el alta como en la edición y durante procesos de reactivación. Esta descripción se incorpora automáticamente en todas las notificaciones por correo electrónico (OTP, avisos de retirada y advertencias).
    • Caducidad Automática (Por Defecto 2 Semanas): Todo asiento cuenta con una fecha de caducidad (expires_at), inicializada por defecto a 14 días desde su registro. La columna expiry_status_badge muestra de un vistazo el tiempo restante (⏳ 13d 22h restantes), alertas de expiración próxima (⚠️ 36h restantes) o estado expirado (⏱️ Caducado).
    • Plantilla de Correo Corporativo (📋 / 📨):
      • Botón 📋 Copiar texto correo en el listado para copiar instantáneamente al portapapeles el texto oficial corporativo con el nombre del archivo, su descripción, el Hash SHA-256 y el enlace directo de acceso.
      • Panel en el detalle del documento con visor del texto preformateado, botón de copia y enlace directo para abrir el cliente de correo (mailto:).
    • Selector de Política de Destrucción (burn_policy):
      • ⚡ 1er Acceso (FIRST_ACCESS): Trituración y borrado físico inmediato tras el primer canje exitoso.
      • 👥 Todos (ALL_RECIPIENTS): Cada destinatario autorizado dispone de una descarga individual; el archivo se preserva en disco hasta que todos los destinatarios hayan canjeado su copia.
    • Verificación Dinámica y Reactivación: Cálculo de SHA-256 en cliente con WebCrypto API; detecta si el documento ya existe y si hay destinatarios previos con canje pendiente, ofreciendo el botón ➕ Volver a añadir pendientes a la lista de correos para reactivarlo sin colisiones y permitiendo actualizar la descripción.
    • Inmutabilidad y No Repudio Legal (Prohibición de Borrado): Los asientos (EncryptedDocument) y las pistas de auditoría (DocumentAccessLog) son estrictamente inmutables. El borrado está deshabilitado a nivel de interfaz (has_delete_permission = False, eliminación de la acción en lote delete_selected) y bloqueado a nivel de modelo ORM (delete() arroja PermissionDenied).
    • Finalización de Asiento y Trituración Segura (⏹️): En lugar de borrar asientos, el personal autorizado dispone del botón ⏹️ Finalizar que redirige a una pantalla de confirmación exigiendo un motivo obligatorio. Al confirmar, el sistema tritura físicamente el archivo en disco (shred_and_delete_file), marca el asiento como consumido (is_consumed=True) y asienta la vicisitud finalizacion_manual en el log de auditoría con el motivo y usuario responsable.
    • Descarga de Auditoría Administrativa: Botón y acción que permite al personal staff con permiso can_audit_download descargar una copia descifrada para fines legales o de auditoría mientras el documento no haya sido consumido, sin destruir el archivo ni marcarlo como consumido, registrando admin_descarga_preservada.
    • Control de Acceso y Permisos Estrictos de Django:
      • Toda la autorización de acciones recae estrictamente en el sistema de permisos de Django (django.contrib.auth.models.Permission).
      • La condición de is_staff solo autoriza el acceso al panel /admin/; no confiere privilegios implícitos ni bypasses sobre los modelos.
      • El botón de finalización (terminate_action_button) y el botón de descarga administrativa (audit_download_button) se filtran dinámicamente según los permisos del usuario (freedec.change_encrypteddocument, freedec.can_audit_download).
      • Inmutabilidad estricta de auditoría: los registros de acceso (DocumentAccessLog) no admiten creación, modificación ni eliminación desde el admin (has_add_permission=False, has_change_permission=False, has_delete_permission=False).
    • Malla de Unidades Organizativas (UO Emisora y Receptora):
      • Los documentos se asocian a una UO Emisora y opcionalmente a una UO Receptora (Malla).
      • Aislamiento estricto de datos: usuarios no-superusuarios solo pueden listar y acceder a los documentos vinculados a sus UOs activas.
      • Atajos inteligentes: botones para autocompletar la lista de destinatarios autorizados con el buzón corporativo de la UO o todos sus miembros activos.
    • Inline de auditoría legal de solo lectura (DocumentAccessLogInline).
  • Panel OrganizationalUnitAdmin e Importación Masiva:

    • Gestión de Unidades Organizativas con código numérico único, alias, correo de buzón y miembros asignados en línea.
    • Módulo interactivo de Carga Masiva JSON (/admin/freedec/organizationalunit/import-batch/) reservado para el Rol Maestro (is_superuser) para aprovisionar simultáneamente UOs y usuarios con feedback en tiempo real.

5. Endpoints de la API REST

1. Solicitud de Código OTP

curl -X POST http://127.0.0.1:8000/freedec/api/public/request-access/ \
  -H "Content-Type: application/json" \
  -d '{
    "file_hash": "4c7ded034bb71b3802a0f17dd37226ff26217f37388d1bc50d3a6bf774091497",
    "email": "destinatario@seguro.gob.es"
  }'

Respuesta:

{
  "status": "processed",
  "message": "Si los datos indicados corresponden a un documento activo y una dirección de correo autorizada, recibirá en breves momentos un código de verificación (OTP) en su buzón."
}

2. Canje y Descarga con OTP

curl -X POST http://127.0.0.1:8000/freedec/api/public/consume/ \
  -H "Content-Type: application/json" \
  -d '{
    "file_hash": "4c7ded034bb71b3802a0f17dd37226ff26217f37388d1bc50d3a6bf774091497",
    "email": "destinatario@seguro.gob.es",
    "otp_code": "455653"
  }' \
  --output documento_descifrado.pdf

6. Comandos de Gestión CLI

# Inicializar entorno staging desatendido
poetry run python manage.py setup_staging --clean

# Carga masiva desatendida de UOs y Usuarios desde archivo JSON
poetry run python manage.py load_batch examples/batch_import_example.json

# Cierre y trituración de asientos caducados (Batch periódico para asientos no canjeados)
poetry run python manage.py close_expired_documents --dry-run
poetry run python manage.py close_expired_documents

# Purga y optimización de base de datos (elimina tokens OTP caducados o usados)
poetry run python manage.py purge_expired_tokens --days=7 --dry-run
poetry run python manage.py purge_expired_tokens

# Listar todos los documentos registrados o finalizar asientos administrativamente
poetry run python manage.py delete_document --list
poetry run python manage.py delete_document <hash_o_archivo>

# Descifrado por OTP mediante CLI (consumo y destrucción Burn-After-Read)
poetry run python manage.py decrypt_document <hash_o_archivo> --otp 123456 --email usuario@empresa.com

# Descarga de auditoría administrativa preservada (Audit Bypass)
poetry run python manage.py decrypt_document <hash_o_archivo> --admin --output copia_auditoria.pdf

7. Formato JSON para Cargas Masivas de UOs y Usuarios

Freedec permite aprovisionar Unidades Organizativas (UO) y Usuarios de forma simultánea tanto desde el panel de administración (/admin/freedec/organizationalunit/import-batch/) como por línea de comandos con load_batch.

El archivo JSON debe seguir la estructura documentada en examples/batch_import_example.json:

{
  "organizational_units": [
    {
      "numeric_code": 1001,
      "alias": "DIRECCION",
      "name": "Dirección General y Presidencia",
      "email": "direccion@freedec.local",
      "description": "Unidad de gobierno corporativo.",
      "is_active": true
    },
    {
      "numeric_code": 1002,
      "alias": "RRHH",
      "name": "Recursos Humanos y Relaciones Laborales",
      "email": "rrhh@freedec.local",
      "description": "Gestión de nóminas y personal.",
      "is_active": true
    }
  ],
  "users": [
    {
      "username": "admin_dir",
      "email": "admin_dir@freedec.local",
      "first_name": "Elena",
      "last_name": "Vázquez",
      "password": "PasswordDir#2026",
      "uo_alias": "DIRECCION",
      "role": "ADMIN",
      "is_staff": true
    },
    {
      "username": "gestor_rrhh",
      "email": "gestor_rrhh@freedec.local",
      "first_name": "Carlos",
      "last_name": "Mendoza",
      "password": "PasswordRRHH#2026",
      "uo_alias": "RRHH",
      "role": "OPERATOR",
      "is_staff": true
    }
  ]
}

Campos admitidos:

  • organizational_units:
    • numeric_code (int, obligatorio): Código numérico único identificativo (ej. 1001).
    • alias (str, obligatorio): Siglas o identificador en mayúsculas (ej. RRHH).
    • name (str, obligatorio): Denominación oficial completa.
    • email (str, obligatorio): Buzón corporativo oficial de la unidad.
    • description (str, opcional): Descripción funcional de la UO.
    • is_active (bool, opcional, por defecto true).
  • users:
    • username (str, obligatorio): Nombre de usuario de acceso.
    • email (str, obligatorio): Correo electrónico seguro del usuario.
    • password (str, opcional): Contraseña inicial (si se omite, se autogenera una segura).
    • uo_alias o uo_numeric_code (obligatorio): UO a la que se vincula el usuario.
    • role (str, obligatorio): Uno de ADMIN (gestión de UO), OPERATOR (emisión/recepción) o AUDITOR (solo lectura y auditoría).
    • is_staff (bool, opcional, por defecto true): Acceso al portal administrativo.

8. Configuración por Archivo INI (freedec.ini) y ConfigParser

A partir de la versión 2.0.0, Freedec centraliza su configuración en un archivo estándar .ini gestionado mediante el módulo nativo de Python configparser, eliminando la dependencia dispersa de variables de entorno sueltas.

Se proporciona una plantilla completa en freedec.ini.template. Copie este archivo a freedec.ini para personalizarlo:

[django]
secret_key = clave_secreta_django
debug = true
allowed_hosts = *

[security]
# Clave maestra Fernet del servidor (32 bytes url-safe base64) para cifrar las DEK
fernet_key = TU_CLAVE_FERNET_BASE64_URL_SAFE_DE_32_BYTES=
max_file_size = 52428800
timing_pbkdf2_iterations = 20000

[email]
# Backend de correo: estándar corporativo SMTP (por defecto, no consola)
backend = django.core.mail.backends.smtp.EmailBackend
host = localhost
port = 25
use_tls = false
use_ssl = false
host_user = 
host_password = 
default_from_email = no-reply@freedec.local
timeout = 5
async_email = true
email_max_workers = 8

[throttling]
web_request_limit_per_minute = 15
api_access_request_rate = 15/minute
api_access_consume_rate = 30/minute

Validación en arranque: FreedecConfig.ready() detiene el inicio de Django con ImproperlyConfigured si fernet_key no es válida o está ausente. En producción, el backend SMTP garantiza la entrega real de las contraseñas temporales OTP.

8.1. Jerarquía de Búsqueda Automática del .ini (Linux y Windows)

Tanto si Freedec se ejecuta de forma autónoma (standalone) como si se usa integrada a través de las funciones de abstracción, el sistema resuelve la ruta del .ini mediante resolve_freedec_ini_path siguiendo este orden de prelación:

  1. Ruta explícita indicada en la función de abstracción:
    • Vía parámetro ini_file en inject_freedec_settings(globals(), ini_file="...") o get_freedec_defaults(ini_file="...").
    • Vía variable de entorno FREEDEC_INI_PATH.
    • Nota: Si la ruta indicada es un directorio, buscará automáticamente freedec.ini en su interior.
  2. En el raíz del sistema de archivos, en una carpeta que ponga freedec:
    • Linux / Unix: /freedec/freedec.ini (y /etc/freedec/freedec.ini).
    • Windows: C:\freedec\freedec.ini y <SystemDrive>\freedec\freedec.ini.
    • Multiplataforma unificada: Path(root.anchor) / "freedec" / "freedec.ini".
  3. En el directorio raíz del proyecto (BASE_DIR):
    • BASE_DIR / "freedec" / "freedec.ini" (en la carpeta freedec del proyecto).
    • BASE_DIR / "freedec.ini" (directamente en la raíz del proyecto).
  4. En el directorio actual de trabajo (cwd):
    • ./freedec/freedec.ini o ./freedec.ini.
  5. Plantillas fallback:
    • freedec.ini.template en la raíz del proyecto o integrada en el paquete Freedec.

9. Acoplamiento e Integración en Proyectos Django Existentes

Freedec está concebido arquitectónicamente como una Django Reusable App lista para acoplarse directamente a cualquier proyecto Django preexistente (monolito corporativo o backend modular) sin fricciones ni conflictos con configuraciones preexistentes.

A partir de la versión 2.0.0, Freedec incluye el módulo freedec.conf con asistentes nativos diseñados específicamente para resolver la configuración en una sola línea.

9.1. Instalación del Paquete

# Vía Poetry
poetry add git+https://github.com/jrubioh1/Freedec.git

# O vía pip
pip install git+https://github.com/jrubioh1/Freedec.git

9.2. Configuración en settings.py del Proyecto Anfitrión

Se ofrecen dos alternativas equivalentes:

🟢 Método A: Asistente Automático de 1 Línea (Recomendado)

Añada al final del archivo settings.py de su proyecto Django anfitrión:

from freedec import inject_freedec_settings

# Inyecta y fusiona de forma segura toda la configuración necesaria
inject_freedec_settings(globals())

El asistente inject_freedec_settings(globals()):

  1. Detección inteligente de configuración: Resuelve automáticamente freedec.ini buscando en el raíz del sistema (/freedec/freedec.ini en Linux o C:\freedec\freedec.ini en Windows), en la carpeta freedec del proyecto (BASE_DIR / "freedec"), en la raíz del proyecto (BASE_DIR / "freedec.ini"), o la ruta/carpeta personalizada pasada en ini_file.
  2. INSTALLED_APPS: Registra rest_framework y freedec.apps.FreedecConfig sin duplicar elementos existentes.
  3. MIDDLEWARE: Detecta y añade django.middleware.locale.LocaleMiddleware inmediatamente después de SessionMiddleware para habilitar el soporte multi-idioma (Español / Inglés).
  4. REST_FRAMEWORK (Mezcla No Destructiva): Fusiona las tasas de throttling (access_request y access_consume) y throttles anónimos en DEFAULT_THROTTLE_RATES sin sobreescribir ni romper las clases de autenticación (JWT, Token, Session) o permisos configuradas por el anfitrión.
  5. Caché y Almacenamiento: Garantiza un backend de caché (LocMemCache) y rutas de MEDIA_URL / MEDIA_ROOT seguras si no estaban previamente definidas.
  6. Correo SMTP Asíncrono: Configura el backend estándar SMTP corporativo y el pool de workers en segundo plano.

Sobreescritura dinámica de parámetros: Puede sobreescribir cualquier clave pasando argumentos con nombre a inject_freedec_settings:

inject_freedec_settings(
    globals(),
    ini_file="config/entorno_produccion.ini",
    FREEDEC_MAX_FILE_SIZE=25 * 1024 * 1024,  # Límite a 25 MB
    FREEDEC_EMAIL_MAX_WORKERS=16,
)

🛠️ Método B: Configuración Manual y Granular

Si su proyecto utiliza múltiples ficheros de configuración modular (base.py, production.py) o desea declarar explícitamente cada directiva:

from pathlib import Path

# 1. Aplicaciones instaladas
if "rest_framework" not in INSTALLED_APPS:
    INSTALLED_APPS.append("rest_framework")
if "freedec.apps.FreedecConfig" not in INSTALLED_APPS:
    INSTALLED_APPS.append("freedec.apps.FreedecConfig")

# 2. Middleware multi-idioma
if "django.middleware.locale.LocaleMiddleware" not in MIDDLEWARE:
    MIDDLEWARE.insert(
        MIDDLEWARE.index("django.contrib.sessions.middleware.SessionMiddleware") + 1,
        "django.middleware.locale.LocaleMiddleware"
    )

# 3. Seguridad criptográfica de Freedec
FREEDEC_FERNET_KEY = "TU_CLAVE_FERNET_BASE64_URL_SAFE_DE_32_BYTES="
FREEDEC_MAX_FILE_SIZE = 50 * 1024 * 1024  # 50 MB
FREEDEC_TIMING_PBKDF2_ITERATIONS = 20000

# 4. Correo electrónico corporativo (SMTP Estándar)
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.tu-entorno.es"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "notificaciones@tu-entorno.es"
EMAIL_TIMEOUT = 5
FREEDEC_ASYNC_EMAIL = True
FREEDEC_EMAIL_MAX_WORKERS = 8

# 5. Throttling anti-ataques de fuerza bruta
REST_FRAMEWORK = {
    **REST_FRAMEWORK,  # Preserva autenticaciones previas
    "DEFAULT_THROTTLE_CLASSES": [
        "rest_framework.throttling.AnonRateThrottle",
    ],
    "DEFAULT_THROTTLE_RATES": {
        **REST_FRAMEWORK.get("DEFAULT_THROTTLE_RATES", {}),
        "anon": "100/minute",
        "access_request": "15/minute",
        "access_consume": "30/minute",
    },
}
FREEDEC_WEB_REQUEST_LIMIT_PER_MINUTE = 15

# 6. Almacenamiento y Caché
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"

9.3. Enrutamiento en urls.py del Proyecto Anfitrión

Incorpore el espacio de nombres de Freedec en el urls.py principal de su proyecto:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("freedec/", include("freedec.urls")),  # Rutas Web GUI y API REST
]

Rutas expuestas automáticamente:

  • Web GUI:
    • /freedec/solicitar/: Formulario de solicitud de clave OTP por Hash SHA-256 y correo.
    • /freedec/canjear/: Canje de OTP de 6 dígitos y descarga en streaming.
  • API REST:
    • /freedec/api/public/request-access/ (POST con file_hash y email).
    • /freedec/api/public/consume/ (POST con file_hash, email y otp_code).
  • Django Admin:
    • /admin/freedec/encrypteddocument/: Panel corporativo de documentos y auditoría.
    • /admin/freedec/organizationalunit/: Malla multi-tenant de UOs y panel de importación JSON.

9.4. Migraciones y Despliegue en el Proyecto Anfitrión

Ejecute las migraciones de Freedec en su base de datos anfitriona:

# Aplica la migración consolidada única 0001_initial
python manage.py migrate

# Opcional: Aprovisionar UOs y usuarios iniciales desde JSON
python manage.py load_batch ruta/a/tu_plantilla_uos.json


🇬🇧 English: Freedec Guide

Welcome to Freedec, a security-focused Django application for unattended delivery and redemption of confidential documents with personal data, based on strict SHA-256 file hash matching and real-time One-Time Password (OTP) verification.


🛡️ Design Principles & Golden Rules

  1. ZERO CLIENT BINARY TRANSPORT: The client NEVER uploads the .enc file to identify themselves. The official locator is exclusively the SHA-256 hash (64 hex characters).
  2. ZERO HUMAN-READABLE PASSWORDS: No plaintext passwords managed by users or admins. Decryption is 100% internal and unattended in RAM after validating the OTP.
  3. BURN-AFTER-READ WITH SECURE DESTRUCTION (Zeroization/Shredding): Upon the first successful redemption by an authorized user, the encrypted file on disk is overwritten with cryptographically random bytes (os.urandom), flushed and synced to physical storage (flush() / os.fsync()), and deleted from the filesystem (os.remove()).

📑 Table of Contents

  1. Cryptographic Lifecycle
  2. Testing & Sandbox Setup
  3. Web GUI Usage
  4. Django Admin Management
  5. REST API Endpoints
  6. CLI Management Commands
  7. Security Configuration in settings.py

1. Cryptographic Lifecycle

  • Upload (Admin): File validated by Magic Bytes, unique DEK generated with Fernet.generate_key(), encrypted in storage as .enc, DEK encrypted with FREEDEC_FERNET_KEY. SHA-256 provided to recipient as sole locator.
  • Access Request: User submits SHA-256 and email at /freedec/solicitar/. If unauthorized or non-existent, simulated PBKDF2 runs to prevent timing attacks. If consumed, email notice is dispatched and intento_post_consumo logged. If active and authorized, 6-digit cryptographic OTP is sent with 15-minute strict expiration.
  • Redemption (Burn-After-Read): User enters 6-digit OTP at /freedec/canjear/. Validated via secrets.compare_digest (locked after 3 failed attempts). File decrypted in memory, physical file on disk shredded with os.urandom, and delivered as FileResponse attachment.

2. Testing & Sandbox Setup

git clone https://github.com/jrubioh1/Freedec.git
cd Freedec
poetry install
poetry run python manage.py migrate
poetry run python manage.py setup_staging
poetry run pytest -v
poetry run python scripts/demo_flow.py

3. Web GUI Usage

  • Request Access (/freedec/solicitar/): SHA-256 hash and email input. Supports ?hash=... prefilling.
  • Redeem OTP (/freedec/canjear/): 6-digit OTP input with immediate browser RAM streaming download and disk shredding.

4. Django Admin Management

  • EncryptedDocumentAdmin Dashboard:

    • Columns: original_filename, file_hash, burn_policy, consumption_status_badge, expiry_status_badge, audit_download_button, corporate_email_button, terminate_action_button.
    • Zero Passwords: No field displays or stores human-readable passwords.
    • Editable Document Description: Pre-filled default corporate description, editable upon upload, document modification, and during reactivation. Embedded automatically into all email notifications (OTP verification, redemption notices, post-consumption warnings).
    • Automatic Expiration (Default 2 Weeks): Every entry includes an expiration date (expires_at), initialized by default to 14 days from creation. The expiry_status_badge column provides an at-a-glance badge of time remaining (⏳ 13d 22h remaining), warning alerts for pending expiration (⚠️ 36h remaining), or expired status (⏱️ Caducado).
    • Corporate Email Template (📋 / 📨):
      • Changelist action button (📋 Copiar texto correo) for one-click clipboard copying of the official notification text with filename, description, SHA-256 hash, and direct access link.
      • Document detail panel featuring a preformatted template viewer, copy button, and direct mailto: link.
    • Destruction Policy Selector (burn_policy):
      • ⚡ 1st Access (FIRST_ACCESS): Immediate physical shredding and removal upon the first successful redemption.
      • 👥 All Recipients (ALL_RECIPIENTS): Each authorized recipient receives an individual download; the file remains on disk until all recipients have redeemed their copy.
    • Dynamic Client-Side Verification & Reactivation: Computes SHA-256 in the browser via WebCrypto API; detects if the document already exists and if prior recipients have pending access, providing a ➕ Add pending to recipient list button to reactivate without hash collisions while allowing description updates.
    • Strict Immutability & Legal Non-Repudiation (Deletion Disabled): Entries (EncryptedDocument) and audit logs (DocumentAccessLog) are strictly immutable. Deletion is disabled in Django Admin (has_delete_permission = False, removal of batch delete_selected) and forbidden at the ORM model level (delete() raises PermissionDenied).
    • Entry Termination & Secure Physical Shredding (⏹️): Authorized staff can terminate active entries via the ⏹️ Finalizar button, which opens a confirmation page requiring a mandatory justification reason. Confirmation physically shreds the file (shred_and_delete_file), marks the document as consumed (is_consumed=True), and registers a finalizacion_manual vicisitud in the audit log preserving all historical evidence.
    • Administrative Audit Inspection: Action and button allowing staff users with explicit freedec.can_audit_download permission to download a decrypted copy for legal compliance while the document has not been consumed, without destroying the file or marking it as consumed, logging admin_descarga_preservada.
    • Strict Django Model Permissions:
      • All authorization actions strictly rely on Django's model permission system (django.contrib.auth.models.Permission).
      • Being is_staff only grants access to /admin/; it never bypasses model-level authorization.
      • Action buttons (terminate_action_button, audit_download_button) are conditionally displayed based on active user permissions (freedec.change_encrypteddocument, freedec.can_audit_download).
      • Audit log immutability: DocumentAccessLog records cannot be added, altered, or deleted manually from Django Admin (has_add_permission=False, has_change_permission=False, has_delete_permission=False).
    • Organizational Unit Mesh (Origin & Target UO):
      • Documents are linked to an Origin UO and optionally a Target UO (Mesh).
      • Strict multi-tenant isolation: non-superuser staff members can strictly view and operate documents associated with their active UO memberships.
      • Interactive helpers: buttons to auto-populate authorized recipient lists with the target UO's corporate mailbox or all active departmental members.
    • Read-only legal access logs inline (DocumentAccessLogInline).
  • OrganizationalUnitAdmin & Bulk Provisioning:

    • Manage flat Organizational Units with unique numeric code, alias, corporate email, and member inlines.
    • Interactive JSON Bulk Import dashboard (/admin/freedec/organizationalunit/import-batch/) reserved for the Master Role (is_superuser) for simultaneous, idempotent provisioning of UOs and users.

5. REST API Endpoints

  • POST /freedec/api/public/request-access/ (file_hash, email)
  • POST /freedec/api/public/consume/ (file_hash, email, otp_code)

6. CLI Management Commands

  • poetry run python manage.py load_batch config_provisioning.json
  • poetry run python manage.py close_expired_documents --dry-run
  • poetry run python manage.py close_expired_documents
  • poetry run python manage.py purge_expired_tokens --days=7 --dry-run
  • poetry run python manage.py purge_expired_tokens
  • poetry run python manage.py delete_document --list
  • poetry run python manage.py delete_document <hash_or_filename>
  • poetry run python manage.py decrypt_document <hash> --otp 123456 --email user@corp.com
  • poetry run python manage.py decrypt_document <hash> --admin --output audit.pdf

7. Security Configuration in settings.py

# Mandatory Fernet master key (32 bytes base64 url-safe)
# Generated via cryptography.fernet.Fernet.generate_key().decode()
FREEDEC_FERNET_KEY = "YOUR_FERNET_KEY_BASE64_URL_SAFE_32_BYTES="

# Maximum allowed file upload size (default 50 MB)
FREEDEC_MAX_FILE_SIZE = 50 * 1024 * 1024

Startup validation: FreedecConfig.ready() halts Django startup with ImproperlyConfigured if FREEDEC_FERNET_KEY is missing or invalid.


8. Integration into Host Django Projects

Freedec is designed as a modular, pluggable Django Reusable App. It can be integrated into any existing Django codebase with minimal effort.

Starting with v2.0.0, Freedec includes freedec.conf providing helper functions to inject settings into any host project automatically.

Add to the end of your host settings.py:

from freedec import inject_freedec_settings

# Automatically merges apps, middleware, throttles, SMTP, caches, and storage
inject_freedec_settings(globals())

What inject_freedec_settings(globals()) does:

  • Discovers and loads freedec.ini by hierarchical search: filesystem root (/freedec/freedec.ini on Linux, C:\freedec\freedec.ini on Windows), project freedec/ subfolder, project root, or custom path passed to ini_file.
  • Appends rest_framework and freedec.apps.FreedecConfig to INSTALLED_APPS without duplicates.
  • Inserts django.middleware.locale.LocaleMiddleware immediately after SessionMiddleware.
  • Merges throttling rates (access_request, access_consume) into REST_FRAMEWORK without altering existing authentication or permission classes.
  • Ensures a valid CACHES backend (LocMemCache) and MEDIA_ROOT / MEDIA_URL paths.
  • Configures corporate SMTP email settings and asynchronous worker pools.

Method B: Manual Granular Configuration

For partitioned settings architectures (base.py, production.py):

INSTALLED_APPS += [
    "rest_framework",
    "freedec.apps.FreedecConfig",
]

MIDDLEWARE += [
    "django.middleware.locale.LocaleMiddleware",
]

FREEDEC_FERNET_KEY = "YOUR_FERNET_KEY_BASE64_URL_SAFE_32_BYTES="
FREEDEC_MAX_FILE_SIZE = 50 * 1024 * 1024
FREEDEC_TIMING_PBKDF2_ITERATIONS = 20000

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.corp.local"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "no-reply@corp.local"
FREEDEC_ASYNC_EMAIL = True
FREEDEC_EMAIL_MAX_WORKERS = 8

REST_FRAMEWORK = {
    **REST_FRAMEWORK,
    "DEFAULT_THROTTLE_CLASSES": [
        "rest_framework.throttling.AnonRateThrottle",
    ],
    "DEFAULT_THROTTLE_RATES": {
        **REST_FRAMEWORK.get("DEFAULT_THROTTLE_RATES", {}),
        "anon": "100/minute",
        "access_request": "15/minute",
        "access_consume": "30/minute",
    },
}

URL Configuration

Include Freedec URLs in your host urls.py:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("freedec/", include("freedec.urls")),
]

Apply Migrations

python manage.py migrate

Metadata

Release files for freedec 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for freedec 2.0.0
File Size Uploaded Provenance
freedec-2.0.0.tar.gz 147.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for freedec 2.0.0
File Interpreter ABI Platform
freedec-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 308.9 kB

Release files / freedec-2.0.0.tar.gz

Download URL freedec-2.0.0.tar.gz
Size 147.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7e46cc5cb1c40dd5240e88b9a0cff6fc83e5e5a5e53146abca8f26eaf824970b
BLAKE2b-256 checksum
How to use checksums
2151f98b37657d7d54bfc10a83ac7aa584ed3eeb8868c27d54339cf0b1d23fc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.5.1 CPython/3.14.9 Linux/7.2.8-gentoo-dist-hardened

Release files / freedec-2.0.0-py3-none-any.whl

Download URL freedec-2.0.0-py3-none-any.whl
Size 161.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9f7d011f7a5d3268d2146ed57bab844bfd004c57c4882610a8e57fef1de34ad7
BLAKE2b-256 checksum
How to use checksums
84e377c786401cd305ff48807e133175c3452f25fcb966ceeaf898a6c983e2c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.5.1 CPython/3.14.9 Linux/7.2.8-gentoo-dist-hardened

Security for freedec 2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page