Reemplaza derivación SHA256 por PBKDF2-HMAC-SHA256 (600k iter) con salt aleatorio por tenant + DEK de 32 bytes aleatoria por cifrado. Robar la DB sin FERNET_KEY o FERNET_KEY sin la DB ya no alcanza para comprometer credenciales. Compatibilidad v1 preservada para migración. Agrega migrar_vault_v3.py con dry-run, pre-flight check y backup atómico. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.7 KiB
8.7 KiB
Changelog — Pedrito Hechakuaa
Todos los cambios notables se documentan acá.
Formato: Keep a Changelog
Versiones: Semantic Versioning
[Unreleased]
[0.4.0] — 2026-05-26
Security
- Envelope encryption v3 en
vault.py— credenciales cifradas en dos capas independientes:- DEK (Data Encryption Key): 32 bytes aleatorios, única por operación de cifrado.
- Wrapping Key: derivada de
FERNET_KEYcon PBKDF2-HMAC-SHA256, 600k iteraciones, salt de 16 bytes aleatorio por tenant. ~200ms por derivación — fuerza bruta inviable incluso con GPU. - Formato en DB:
{"v":3,"s":"<salt_b64>","k":"<dek_enc>","p":"<payload_enc>"} - Propiedades: robar la DB sin
FERNET_KEYes inútil; robarFERNET_KEYsin la DB también.
- Cache de wrapping keys (
lru_cache) — evita ejecutar PBKDF2 600k iter por cada tenant en cada ciclo del poller. Cache key incluye fingerprint del KEK para invalidar si cambiaFERNET_KEY. - Compatibilidad v1 preservada —
descifrar_credencialesdetecta automáticamente formato v1 (Fernet token puro) vs v3 (JSON). No se generan nuevas v1.
Added
scripts/migrar_vault_v3.py— migración segura de credenciales v1 → v3:- Verifica que todos los tenants v1 sean descifrables ANTES de tocar la DB (aborta si alguno falla).
- Backup automático de la DB antes de cualquier escritura.
- Flag
--dry-runpara ver qué haría sin modificar nada. - Commit atómico: o migra todos o no migra ninguno.
[0.3.1] — 2026-05-26
Security
/health/historyrequiere auth —Authorization: Bearer <HEALTH_AUTH_TOKEN>; sin token devuelve 401 con headerWWW-Authenticate. Sin auth configurada, retorna 401 igualmente.- chat_ids enmascarados en historial — reemplazados por hash SHA256[:8] opaco (
usr_a3b4c5d6); preserva correlación de eventos sin exponer Telegram IDs (PII). /healthpúblico mínimo — sin auth devuelve solo{status, timestamp}. Con auth, respuesta completa con métricas internas. Elimina exposición de conteo de tenants y timing del poller.- Env vars borradas del proceso — después de cargar
Settings(), se eliminan deos.environ:FERNET_KEY,TELEGRAM_BOT_TOKEN,PJ_USUARIO_ENC,PJ_PASSWORD_ENC,WEBHOOK_SECRET,HEALTH_AUTH_TOKEN,INVITE_CODE. Protege contra/proc/<pid>/environ. - Race condition TOCTOU en invite codes eliminada —
SELECT + UPDATEreemplazado porUPDATE WHERE codigo=? AND usado=0;rowcount=0indica código no válido o ya usado. Imposible que dos requests simultáneos consuman el mismo código. - Timing oracle en validación de código mitigado — delay mínimo garantizado de 800ms en
_paso_codigo()independientemente del resultado;secrets.compare_digest()para comparación contra código del.env. - Respuestas a usuarios no registrados reducidas al mínimo —
_rechazar_no_registradoya no revela la arquitectura de comandos; texto libre de usuarios sin registro recibe silencio total. - Webhook inválido devuelve 404 — en vez de 403, no confirma la existencia del endpoint.
- Nginx rate limiting documentado en
DEPLOY.md:limit_req_zone30r/s para webhook, 10r/min para health; headersX-Content-Type-Options,X-Frame-Options. HEALTH_AUTH_TOKENagregado aconfig.pyy a la guía de.envenDEPLOY.md.
[0.3.0] — 2026-05-25
Added
- Docker —
Dockerfile(imagenghcr.io/astral-sh/uv:python3.12-bookworm-slim),docker-compose.ymlconrestart: unless-stoppedy healthcheck,.dockerignore. - Health check HTTP (
health.py) — servidor aiohttp en puerto 8080:GET /health— estado del bot (ok/degraded)GET /health/history— últimos N eventos del audit log- Watcher loop que alerta al admin via Telegram si el poller no actualiza en N horas
- Schema migrations — directorio
migrations/001_initial_schema.sql, funciónrun_migrations()endatabase.py; idempotente conCREATE TABLE IF NOT EXISTS. Tablaschema_migrationslleva registro de versiones aplicadas. - Webhook opt-in —
POST /webhooken aiohttp validaX-Telegram-Bot-Api-Secret-Tokenconcompare_digesty pone el Update enapplication.update_queuede PTB. Se activa conWEBHOOK_URLen.env; vacío = long-polling. aiohttp>=3.9como nueva dependencia.WEBHOOK_URL,WEBHOOK_SECRET,HEALTH_PORT,HEALTH_ALERT_HOURSenconfig.py.- Poller notifica a health vía callback
on_poll_done(tenant_count). revisar_ahora()retornaint(cantidad de tenants revisados).
Changed
init_db()reemplazado porrun_migrations()enmain.py;init_db()queda como alias para compatibilidad con scripts.main.pyarrancaHealthServerantes del poller; elige polling vs webhook según config; registra webhook con Telegram en modo webhook; elimina webhook al detener.DEPLOY.mdactualizado con guía completa de 20 secciones: DNS Bluehost/cPanel (con mensaje exacto en inglés para delegar), Nginx, Certbot/SSL, Docker, webhook, health check, rate limiting.
[0.2.1] — 2026-05-25
Fixed
- Campos del API del PJ corregidos — la API real usa
fechaNotificacion(nofecha),descripcionDespacho(nojuzgado),descripcionCircunscripcion(nocircunscripcion).NotificacionPendiente.__init__ahora usa fallbackorpara ambos nombres. - PDF callback — usaba
cod_notificacion_origencomo ID de actuación; corregido acod_actuacion_caso(campocodActuacionCasode la API). - 403 en
listar_notificaciones— manejado explícitamente comoCSJAuthErroren vez de caer enraise_for_status()genérico.
[0.2.0] — 2026-05-25
Added
- Multi-tenant —
database.pycon SQLite vía aiosqlite; tablatenantscon credenciales cifradas por chat_id;list_active_tenants(),save_tenant(),delete_tenant(). - Onboarding flow (
onboarding.py) — máquina de estados de 8 pasos: código de invitación → consentimiento → nombre → tono → timezone → cédula → password → guardado. - Códigos de invitación — tabla
invite_codes, validación de un solo uso atómica, fallback al código maestro del.env;scripts/generar_codigo.py. - Audit log — tabla
audit_log, funciónaudit.log()fire-and-forget; cobertura de todos los eventos de onboarding, polling, comandos y errores. - Rate limiting (
utils/rate_limiter.py) — ventana deslizante por chat_id, 20 req/60s; reset en/resetear. - FERNET_KEY rotation (
scripts/rotar_fernet_key.py) — re-cifra todos los tenants de forma atómica; hace backup de.envantes de modificar; aborta si algún tenant falla. - Comando
/exp— búsqueda de expedientes por número o carátula. - Comando
/pdf— descarga PDF de la actuación más reciente viapermisoFirmado. - Tono personalizable por abogado: formal / cotidiano / informal.
- Zona horaria configurable por abogado.
TELEGRAM_EXTRA_IDSpara autorizar IDs adicionales sin onboarding.DEPLOY.md— primera versión de la guía de despliegue en VPS Ubuntu con systemd.
Changed
poller.pyitera sobre todos los tenants activos (era single-tenant).- Snapshots por tenant:
data/snapshot_{chat_id}.json(eradata/snapshot.jsonglobal). vault.pyusa derivación de clave Fernet por chat_id:base64(SHA256(FERNET_KEY + str(chat_id))).
Security
- Contraseña del PJ borrada de memoria inmediatamente tras cifrar (
del passworden onboarding). - Mensaje de Telegram con la contraseña eliminado del chat vía
delete_messageantes de procesar.
[0.1.0] — 2026-05-25
Added
- Login al sistema judicial
apps.csj.gov.py:GET /login→ cookiecookiesession1→POST /autenticador/login→ bearer token (TTL 1h). - Polling de
GET /Notificaciones/PorRecibircada N minutos en horario hábil (lun-vie, 7-18hs). - Diff vs snapshot JSON local — solo notifica notificaciones con
codNotificacionOrigennuevo. - Relogin automático transparente al expirar el token.
- Bot de Telegram con comandos:
/start,/notif,/estado,/ayuda,/salir. - Credenciales del PJ cifradas con Fernet en
.env(scripts/cifrar_credenciales.py). scrub()enutils/sanitize.py— sanitiza bearer tokens, JWTs, cookies y passwords antes de pasar cualquier dato externo a los logs.- Logging estructurado con
structlog(JSON en prod, ConsoleRenderer en dev víaisatty). - Configuración vía
pydantic-settings— único punto de config de la app (config.py). - Stack base:
httpx,python-telegram-bot[ext] v21,aiosqlite,cryptography,structlog,pydantic-settings,apscheduler. - Manejo de señales
SIGINT/SIGTERMpara shutdown limpio.