══════════════════════════════════════════════════════════════════════ 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
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= 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.