resetea.net/CONTEXT.txt

209 lines
10 KiB
Text

══════════════════════════════════════════════════════════════════════
RESETEA.NET — CONTEXTO DEL PROYECTO
Actualizado: 2026-04-20
══════════════════════════════════════════════════════════════════════
QUÉ ES
──────
Herramienta web de privacidad digital. Ayuda a los usuarios a reducir
su huella digital: enviar cartas GDPR, eliminar cuentas en redes
sociales, desindexar datos de buscadores y contactar con data brokers.
Principio fundamental: PRIVACY-FIRST.
· No se almacena ningún dato personal (PII).
· Sin cookies, sin tracking, sin analytics.
· La generación de cartas en plantillas.html es 100% local (JS en navegador).
· El único dato que pasa por el servidor es el email para reenvío GDPR,
y solo se guarda un hash SHA-256 truncado (12 chars) como referencia.
ARQUITECTURA GENERAL
────────────────────
Internet
└── Nginx (puerto 80 → redirect HTTPS / puerto 443 SSL)
├── / → archivos estáticos en public/
└── /api/* → proxy → Node.js en 127.0.0.1:8787
└── Nodemailer → sendmail (MTA local)
└── Postfix → relay Brevo SMTP (smtp-relay.brevo.com:587)
└── opendkim (firma DKIM, selector: mail, 2048-bit RSA)
└── Google APIs (opcional: Gmail OAuth, CSE)
└── SearXNG (instancias públicas, fallback egosearch)
INFRAESTRUCTURA DE EMAIL
────────────────────────
Problema: IP dinámica del router → reputación de envío comprometida.
Solución: relay via Brevo (free tier, 300 emails/día).
· Postfix configurado como relay hacia smtp-relay.brevo.com:587
· Credenciales en /etc/postfix/sasl_passwd (script: infra/set-relay-credentials.sh)
· DKIM signing con opendkim — selector "mail", clave en /etc/opendkim/keys/resetea.net/
· DNS gestionado via Gandi LiveDNS API — script: /home/capitansito/HOST/managedns.sh
Registros DNS configurados:
SPF: "v=spf1 include:spf.brevo.com include:_mailcust.gandi.net ~all"
DKIM: mail._domainkey.resetea.net TXT (clave pública 2048-bit RSA)
DMARC: _dmarc.resetea.net TXT "v=DMARC1; p=none; rua=mailto:dmarc@resetea.net"
→ Cuando el envío sea estable varios días, subir p=none a p=quarantine
Scripts de infraestructura:
infra/setup-mail.sh — instala Postfix, opendkim, genera clave DKIM
infra/set-relay-credentials.sh — escribe /etc/postfix/sasl_passwd con login Brevo
HOST/managedns.sh — actualiza IP dinámica en Gandi (NO toca registros mail)
Comando: setup-mail-dns para configurar SPF/DKIM/DMARC
Proceso Node.js:
Servicio: /etc/systemd/system/resetea.service
Node binary: /home/capitansito/.nvm/versions/node/v18.20.8/bin/node
Arranque: sudo systemctl restart resetea
PÁGINAS PÚBLICAS (public/)
───────────────────────────
index.html — Página principal. REDISEÑADA EN ESTA SESIÓN.
Secciones:
1. Hero: título "RESETEA" + lema "La información es poder. Quitémosles poder."
Carrusel de citas (5 frases, rota cada 6s):
- "Matamos gente basándonos en metadatos." (Gen. Hayden, NSA)
- Edward Snowden sobre privacidad
- Parafraseando Orwell, 1984
- "No somos clientes, somos el producto." (Serra & Schoolman, 1973)
- "La vigilancia es el modelo de negocio de internet." (Schneier)
2. Formulario GDPR (DISEÑO DOS COLUMNAS — nuevo):
Columna izquierda (Paso 1): email input + lista de privacidad
Columna derecha (Paso 2): selección de redes
· Grid de chips AUTO-GDPR (instagram, facebook, twitter_x, linkedin,
tiktok, snapchat, discord, reddit, microsoft, apple, google, amazon)
→ seleccionables, al enviar se manda carta GDPR via API o se abre form
· Grid de chips MANUALES (whatsapp, telegram, spotify, youtube,
netflix, twitch, pinterest)
→ ACCIÓN DIRECTA: clic abre el enlace oficial inmediatamente
→ NO son seleccionables, NO cuentan para el botón "Enviar"
→ Borde discontinuo, flash verde al hacer clic
· Botón "Seleccionar todas" (solo auto-chips)
· Contador "X redes seleccionadas"
Botón "Enviar cartas GDPR (X)" — solo activo con email válido + al menos 1 auto-chip
3. Panel de acciones completo (REDISEÑADO — secciones visibles, sin tabs):
Barra de progreso global (todos los checkboxes)
6 secciones siempre visibles apiladas verticalmente, cada una con:
· Badge pill con nombre en fuente Recion (Cuentas base, Redes sociales,
Mensajería, Streaming, Buscadores, Data brokers)
· Botón "Marcar todas" (header) y "✓ Marcar sección completada" (footer)
· Grid de tarjetas con: logo oficial + nombre + botones de acción
· Al marcar checkbox: tarjeta se vuelve verde irlandés (sage)
4. Sección "Cómo funciona" (3 pasos)
5. Sección "Plantillas legales"
6. Aviso legal
Logos: Simple Icons CDN (cdn.simpleicons.org) — pendiente mover a /public/icons/
PENDIENTE: Descargar los SVGs localmente (linkedin, microsoft, amazon,
microsoftbing fallaron — buscar slug correcto en Simple Icons)
stats.html — Dashboard de estadísticas anónimas. NUEVO.
· 4 KPI cards: emails enviados, redireccionados, búsquedas, total
· Gráfico de barras por proveedor
· Explicación detallada de privacidad (sección <details> expandible)
· Fetch a GET /api/stats con credentials:'omit'
· Todo el HTML de servidor pasa por esc() antes de innerHTML (anti-XSS)
plantillas.html — Generador de cartas GDPR (browser-side).
· esc() + safeHref() aplicados a todo HTML dinámico
· Nav: enlace añadido a stats.html
concienciacion.html, tipos.html, egosurfing.html — sin cambios en esta sesión.
SERVICIOS DEL BACKEND (api/)
─────────────────────────────
POST /api/erase
Envía carta GDPR Art. 17 al DPO.
Entrada: { provider, email, [nickname, phone, address, extra] }
Salida: { status: 'ok'|'use_form'|error, reference: hash12chars }
Proveedores API directa (10): instagram, facebook, twitter_x, linkedin,
tiktok, snapchat, microsoft, apple, reddit, discord
Proveedores formulario oficial (2): google, amazon
SEGURIDAD: sin fallback a proveedor desconocido (eliminado open-relay)
GET /api/stats
Devuelve estadísticas anónimas en JSON.
Rate limit: 30 req/min
Datos: total_sent, total_redirected, total_errors, total_searches,
by_provider (solo proveedores whitelisteados)
Almacenamiento: data/stats.json (escritura atómica con .tmp + rename)
SIN PII — solo contadores agregados.
GET /api/egosearch?q=<consulta>
Busca con SearXNG o Google CSE. Límite: 500.000 bytes respuesta.
Registra stats.record({ type: 'search' }) por cada búsqueda.
GET /api/gmail/auth → GET /api/gmail/callback
OAuth2 Google. Estado firmado con HMAC-SHA256 + nonce (anti-forgery).
Token de un solo uso, sin refresh, sin persistencia.
SEGURIDAD IMPLEMENTADA
──────────────────────
FRONTEND:
· esc() en todos los datos del servidor antes de innerHTML
· safeHref() para validar URLs (solo http/https)
· credentials:'omit' en todos los fetch
BACKEND:
· Rate limiting Nginx: 20 req/s, burst 40 para /api/
· Rate limiting Express: general 100/15min, email 10/1h, búsqueda 8/1min, stats 30/1min
· IP real via X-Real-IP desde Nginx ($remote_addr — no spoofeable)
· Helmet: HSTS, X-Frame-Options DENY, CSP estricta, Referrer-Policy, Permissions-Policy
· Anti-CRLF: sanitizeHeader() en campos opcionales del email
· Anti prototype pollution: Object.create(null) en stats.by_provider
· Timeout Slowloris: headersTimeout 10s, requestTimeout 15s en Node
· Timeout Nginx: proxy_read_timeout 15s, connect_timeout 5s
· OAuth state: HMAC-SHA256 con nonce random, base64url, max 4096 bytes
· Mailer: sin fallback a proveedor desconocido
· Stats: safeInt() valida numéricos, VALID_DATE regex valida fecha
DISEÑO Y UI
───────────
Sistema de diseño (index.css):
Variables CSS: --caoba (marrón oscuro), --sage (#1a7a4a, verde irlandés),
--acid (#c8ff00, amarillo ácido), --surface, --bg, --border
Fuentes: Recion/Italiana (serif, para títulos y badges), system-ui (para texto)
Formulario principal:
· Layout dos columnas (grid 340px + 1fr) — sticky email column
· Botones de red: system-ui, 0.97rem, grid auto-fill minmax(130px, 1fr)
· Auto-chips seleccionados: verde irlandés (#1a7a4a)
· Manual chips: borde discontinuo, clic directo
· Mobile: stacks a columna única en ≤720px
Panel de acciones:
· Secciones visibles sin tabs
· Badges: fuente Recion, background caoba, border-radius 20px
· Cards: border 1.5px, border-radius 14px, checked = sage-lt background
· Botones de acción: 0.82rem, padding 0.35rem 0.85rem, border-radius 8px
· Logos: Simple Icons CDN (pendiente mover a /public/icons/ local)
PENDIENTES PARA PRÓXIMA SESIÓN
───────────────────────────────
1. Logos locales: descargar SVGs de Simple Icons con slugs correctos
Fallaron: linkedin, microsoft, amazon, microsoftbing
Intentar desde: https://simpleicons.org/ o el paquete npm simple-icons
Guardar en: public/icons/{slug}.svg
Actualizar src en HTML de /icons/{slug}.svg
2. DNS/mail: revisar logs de envío con journalctl -u postfix
Cuando envío sea estable varios días → subir DMARC a p=quarantine:
Comando: bash /home/capitansito/HOST/managedns.sh setup-mail-dns
(editar el script para cambiar p=none a p=quarantine)
3. Systemd: verificar que resetea.service arranca bien con:
sudo systemctl status resetea
sudo systemctl enable resetea (si no está enabled)
4. Probar flujo completo de email desde la web en producción.
5. Gmail OAuth: requiere credenciales Google Cloud Console en .env
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI
6. Revisar si el ícono de Snapchat (amarillo) es visible sobre fondo claro —
puede necesitar ajuste de contraste.