Freedec: Sistema de Entrega y Canje Desatendido de Documentos Confidenciales
🇪🇸 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
- CERO TRANSPORTE DEL BINARIO POR EL CLIENTE:
El usuario final NUNCA sube el archivo
.encpara 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). - 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.
- BURN-AFTER-READ CON DESTRUCCIÓN SEGURA (Zeroization/Shredding):
Al primer canje exitoso por un usuario autorizado, el archivo cifrado en disco se sobrescribe con bytes criptográficamente aleatorios (
os.urandom(file_size)), forzando la sincronización en disco físico conflush()yos.fsync()antes de desvincularlo del sistema de archivos (os.remove()), y el registro pasa a estado consumido.
📑 Índice de Contenidos
- Flujo Criptográfico y Operativo
- Entorno de Pruebas y Sandbox de Staging
- Uso de la Interfaz Web (Web GUI)
- Gestión en Django Admin
- Endpoints de la API REST
- Comandos de Gestión CLI
- Configuración de Seguridad en settings.py
1. Flujo Criptográfico y Operativo
Alta del Documento (Admin):
- El administrador sube el documento original (PDF, LibreOffice u Office) y especifica la lista de correos autorizados.
- El sistema valida las cabeceras binarias (Magic Bytes) y calcula el hash SHA-256 mediante lectura en bloques de 64 KB (anti-DoS/OOM).
- Genera una Clave Maestra de Datos (DEK) única con
Fernet.generate_key(). - Cifra el contenido del archivo con la DEK y lo guarda en disco como
.enc. - Cifra la DEK internamente con la clave maestra del servidor
settings.FREEDEC_FERNET_KEYy la almacena enencrypted_dek. - El administrador entrega el Hash SHA-256 al usuario como prueba y localizador oficial.
Solicitud de Acceso:
- El usuario final accede a
/freedec/solicitar/e introduce el Hash SHA-256 y su correo electrónico (o mediante enlace con?hash=...). - 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.
- 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), registrandointento_post_consumoen la auditoría. - 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 auditaotp_enviado.
Canje y Destrucción Física (Burn-After-Read):
- El usuario introduce el código OTP en
/freedec/canjear/. - 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). - 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 unFileResponsecon el archivo original en memoria.
2. Entorno de Pruebas y Sandbox de Staging
Instalación con Poetry
# Clonar e instalar dependencias
git clone https://github.com/jrubioh1/Freedec.git
cd Freedec
poetry install
# Aplicar migraciones
poetry run python manage.py migrate
# Inicializar entorno staging (crea superusuario 'admin' / 'admin123' y sample_document.pdf)
poetry run python manage.py setup_staging
Ejecutar Suite de Pruebas Automatizadas
poetry run pytest -v
Ejecutar Demostración Completa 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,audit_download_button,corporate_email_button,delete_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).
- Plantilla de Correo Corporativo (📋 / 📨):
- Botón
📋 Copiar texto correoen 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:).
- Botón
- 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 correospara reactivarlo sin colisiones y permitiendo actualizar la descripción. - Eliminación y Trituración Directa (🗑️): Botón de borrado directo con permisos en cascada sobre tokens y registros de auditoría, ejecutando la destrucción física en disco (
shred_and_delete_file). - Descarga de Auditoría Administrativa: Botón y acción que permite al personal staff con permiso
can_audit_downloaddescargar 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, registrandoadmin_descarga_preservada. - Control de Acceso y Permisos Estrictos de Django:
- Toda la autorización de acciones y capacidades de borrado recae estrictamente en el sistema de permisos de Django (
django.contrib.auth.models.Permission). - La condición de
is_staffsolo autoriza el acceso al panel/admin/; no confiere privilegios implícitos ni bypasses sobre los modelos. - La columna de borrado (
delete_action_button) y el botón de descarga administrativa (audit_download_button) se filtran dinámicamente según los permisos del usuario (freedec.delete_encrypteddocument,freedec.can_audit_download). - Inmutabilidad estricta de auditoría: los registros de acceso (
DocumentAccessLog) no admiten creación ni modificación manual desde el admin (has_add_permission=False,has_change_permission=False) y las filas inline no pueden eliminarse individualmente (can_delete=False). - El borrado de documentos respeta la cascada nativa de Django: si un usuario carece de permisos para borrar los registros dependientes (
DocumentAccessLogoAccessVerificationToken), la operación es bloqueada automáticamente con403 Forbidden.
- Toda la autorización de acciones y capacidades de borrado recae estrictamente en el sistema de permisos de Django (
- Inline de auditoría legal de solo lectura (
DocumentAccessLogInline).
- Columnas:
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
# Listar todos los documentos registrados
poetry run python manage.py delete_document --list
# 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. Configuración de Seguridad en settings.py
# Clave maestra Fernet obligatoria (32 bytes base64 url-safe)
# Generada con cryptography.fernet.Fernet.generate_key().decode()
FREEDEC_FERNET_KEY = "TU_CLAVE_FERNET_BASE64_URL_SAFE_DE_32_BYTES="
# Límite máximo de archivo permitido (50 MB)
FREEDEC_MAX_FILE_SIZE = 50 * 1024 * 1024
Validación en arranque:
FreedecConfig.ready()detiene el inicio de Django conImproperlyConfiguredsiFREEDEC_FERNET_KEYno es válida o está ausente.
🇬🇧 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
- ZERO CLIENT BINARY TRANSPORT: The client NEVER uploads the
.encfile to identify themselves. The official locator is exclusively the SHA-256 hash (64 hex characters). - ZERO HUMAN-READABLE PASSWORDS: No plaintext passwords managed by users or admins. Decryption is 100% internal and unattended in RAM after validating the OTP.
- 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
- Cryptographic Lifecycle
- Testing & Sandbox Setup
- Web GUI Usage
- Django Admin Management
- REST API Endpoints
- CLI Management Commands
- 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 withFREEDEC_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 andintento_post_consumologged. 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 viasecrets.compare_digest(locked after 3 failed attempts). File decrypted in memory, physical file on disk shredded withos.urandom, and delivered asFileResponseattachment.
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
EncryptedDocumentAdminDashboard:- Columns:
original_filename,file_hash,burn_policy,consumption_status_badge,audit_download_button,corporate_email_button,delete_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).
- 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.
- Changelist action button (
- 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 listbutton to reactivate without hash collisions while allowing description updates. - Direct Shredding & Deletion (🗑️): Direct delete button enforcing cascade permissions on tokens and audit logs, performing physical overwriting (
shred_and_delete_file). - Administrative Audit Inspection: Action and button allowing staff users with explicit
freedec.can_audit_downloadpermission to download a decrypted copy for legal compliance while the document has not been consumed, without destroying the file or marking it as consumed, loggingadmin_descarga_preservada. - Strict Django Model Permissions:
- All authorization and delete actions strictly rely on Django's model permission system (
django.contrib.auth.models.Permission). - Being
is_staffonly grants access to/admin/; it never bypasses model-level authorization. - Action buttons (
delete_action_button,audit_download_button) are conditionally displayed based on active user permissions (freedec.delete_encrypteddocument,freedec.can_audit_download). - Audit log immutability:
DocumentAccessLogrecords cannot be added or altered manually (has_add_permission=False,has_change_permission=False), and inline rows cannot be deleted individually (can_delete=False). - Cascade deletion adheres to Django's native permission checks: if a user lacks delete permission on related logs or tokens, deletion is denied with
403 Forbidden.
- All authorization and delete actions strictly rely on Django's model permission system (
- Read-only legal access logs inline (
DocumentAccessLogInline).
- Columns:
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 delete_document --listpoetry run python manage.py decrypt_document <hash> --otp 123456 --email user@corp.compoetry 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 withImproperlyConfiguredifFREEDEC_FERNET_KEYis missing or invalid.
Release files for freedec 1.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| freedec-1.2.1.tar.gz | 89.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| freedec-1.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 201.4 kB
Release files / freedec-1.2.1.tar.gz
| Download URL | freedec-1.2.1.tar.gz |
|---|---|
| Size | 89.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c38a52b5473c6ccfc4c024b278ba102ae8886abd3eaf4e9295784d05bfc03cb2
|
|
BLAKE2b-256 checksum How to use checksums |
692ee6d1768024dd83a048870eb268b9f6c06298c7161d9ec1a1712714591251
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.3 CPython/3.14.7 Linux/7.2.6-gentoo-dist-hardened
|
Release files / freedec-1.2.1-py3-none-any.whl
| Download URL | freedec-1.2.1-py3-none-any.whl |
|---|---|
| Size | 111.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
823df085f86e6ff903925e8e971d0a1defa6ee8dbbc113f1b5cff130c72c90a7
|
|
BLAKE2b-256 checksum How to use checksums |
819e7314e48a35a2164bf5f9096cfd1adc9973e5d1576a23cf58a540491d10a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.3 CPython/3.14.7 Linux/7.2.6-gentoo-dist-hardened
|