From 2bc71b80b79ee003bde84ee3ed8017a9c4fed036 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sun, 8 Mar 2026 18:01:07 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/server.js b/server.js index 30e6efb..3efceab 100644 --- a/server.js +++ b/server.js @@ -461,6 +461,109 @@ app.get("/auth/me", authMiddleware, async (req, res) => { } }); +// ========================================== +// 📝 REGISTRO DE NUEVAS EMPRESAS (SAAS) +// ========================================== +app.post("/auth/register", async (req, res) => { + try { + const { fullName, email, phone, password, dni, address } = req.body; + + if (!email || !password || !fullName || !phone) { + return res.status(400).json({ ok: false, error: "Faltan datos obligatorios" }); + } + + const p = normalizePhone(phone); + + // 1. Verificamos si el email o teléfono ya están en uso + const check = await pool.query("SELECT id FROM users WHERE email = $1 OR phone = $2", [email, p]); + if (check.rowCount > 0) { + return res.status(400).json({ ok: false, error: "El email o teléfono ya están registrados" }); + } + + const hash = await bcrypt.hash(password, 10); + + // 2. Creamos al usuario como ADMIN (dueño de su propia empresa/instancia) + // Lo creamos como NO verificado hasta que ponga el código + const insert = await pool.query(` + INSERT INTO users (full_name, email, phone, password_hash, dni, address, role, status, is_verified) + VALUES ($1, $2, $3, $4, $5, $6, 'admin', 'active', FALSE) + RETURNING id + `, [fullName, email, p, hash, dni || null, address || null]); + + const newUserId = insert.rows[0].id; + + // 3. Le asignamos su propio ID como owner_id (es el jefe de su panel) + await pool.query("UPDATE users SET owner_id = $1 WHERE id = $2", [newUserId, newUserId]); + + // 4. Generamos el código de 6 dígitos para el WhatsApp + const code = genCode6(); + const codeHash = await bcrypt.hash(code, 10); + + await pool.query(` + INSERT INTO login_codes (user_id, phone, code_hash, purpose, expires_at) + VALUES ($1, $2, $3, 'register_verify', NOW() + INTERVAL '15 minutes') + `, [newUserId, p, codeHash]); + + // 5. Enviamos el WhatsApp usando la instancia principal (Aviso en consola por si Evolution no está listo) + console.log(`🔐 [SISTEMA] Código de verificación para ${p}: ${code}`); + const msg = `👋 *¡Bienvenido a IntegraRepara!*\n\nTu código de verificación es: *${code}*\n\nTiene una validez de 15 minutos.`; + + // Intentamos enviarlo si la variable EVOLUTION_INSTANCE existe + if (process.env.EVOLUTION_INSTANCE) { + sendWhatsAppAuto(p, msg, process.env.EVOLUTION_INSTANCE, false).catch(console.error); + } + + res.json({ ok: true, message: "Código enviado" }); + } catch (e) { + console.error("Error en Registro:", e); + res.status(500).json({ ok: false, error: "Error interno del servidor" }); + } +}); + +// ========================================== +// ✅ VERIFICACIÓN DEL CÓDIGO (OTP) +// ========================================== +app.post("/auth/verify", async (req, res) => { + try { + const { phone, code } = req.body; + const p = normalizePhone(phone); + + // Buscamos códigos pendientes para ese teléfono + const q = await pool.query(` + SELECT c.*, u.id as u_id, u.full_name, u.role, u.owner_id + FROM login_codes c + JOIN users u ON c.user_id = u.id + WHERE c.phone = $1 AND c.consumed_at IS NULL AND c.expires_at > NOW() + ORDER BY c.created_at DESC LIMIT 1 + `, [p]); + + if (q.rowCount === 0) return res.status(400).json({ ok: false, error: "Código inválido o caducado" }); + + const codeRecord = q.rows[0]; + const valid = await bcrypt.compare(code, codeRecord.code_hash); + + if (!valid) return res.status(400).json({ ok: false, error: "Código incorrecto" }); + + // Marcamos código como usado y usuario como verificado + await pool.query("UPDATE login_codes SET consumed_at = NOW() WHERE id = $1", [codeRecord.id]); + await pool.query("UPDATE users SET is_verified = TRUE WHERE id = $1", [codeRecord.u_id]); + + // Generamos su token de sesión para que entre directo + const token = signToken({ + id: codeRecord.u_id, + email: codeRecord.email, // Aquí si usaras email en el token + phone: codeRecord.phone, + role: codeRecord.role, + owner_id: codeRecord.owner_id + }); + + res.json({ ok: true, token, user: { id: codeRecord.u_id, full_name: codeRecord.full_name, role: codeRecord.role } }); + } catch (e) { + console.error("Error en Verificación:", e); + res.status(500).json({ ok: false, error: "Error en el servidor" }); + } +}); + // ========================================== // 🕵️ ROBOT NOTARIO (TRAZABILIDAD TOTAL)