'use strict'; const crypto = require('crypto'); const { sendErasureMail, PROVIDER_DATA } = require('../services/mailer'); const ALLOWED_PROVIDERS = new Set(Object.keys(PROVIDER_DATA)); /* Elimina CRLF y chars de control — previene header injection en el cuerpo del email */ function sanitizeField(raw, maxLen) { return String(raw || '') .replace(/[\r\n\t\x00-\x1F\x7F]/g, ' ') // CRLF → espacio, no rompe el texto .replace(/\s{2,}/g, ' ') // colapsa espacios múltiples .trim() .slice(0, maxLen); } module.exports = async (req, res) => { try { const { provider, email, nickname: rawNick, phone: rawPhone, address: rawAddr, extra: rawExtra } = req.body; // Validación mínima if (!provider || !email) { return res.status(400).json({ error: 'provider y email son obligatorios' }); } // Validar proveedor conocido (previene abusos de relay) if (!ALLOWED_PROVIDERS.has(provider)) { return res.status(400).json({ error: 'Proveedor no soportado. Usa el formulario oficial.' }); } // Validación básica de email if (typeof email !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { return res.status(400).json({ error: 'Email inválido' }); } // Sanitizar campos opcionales: longitud + strip CRLF (header injection) const nickname = sanitizeField(rawNick, 100); const phone = sanitizeField(rawPhone, 30); const address = sanitizeField(rawAddr, 300); const extra = sanitizeField(rawExtra, 500); // Hash irreversible para referencia (auditoría sin almacenar PII) const hash = crypto .createHash('sha256') .update(email + (process.env.SALT || 'resetea-default-salt')) .digest('hex'); const result = await sendErasureMail({ provider, email, nickname, phone, address, extra }); if (result.skipped) { return res.json({ status: 'use_form', message: 'Este proveedor no acepta solicitudes por email. Usa su formulario oficial.', formUrl: result.formUrl, reference: hash.substring(0, 12), }); } // PII fuera de scope aquí — solo el hash queda res.json({ status: 'ok', message: 'Solicitud enviada. Guarda el código de referencia.', reference: hash.substring(0, 12), }); } catch (e) { console.error('erase route error:', e.message); res.status(500).json({ error: 'Error interno. Inténtalo de nuevo o usa el formulario oficial del proveedor.' }); } };