209 lines
10 KiB
Text
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.
|