From 3720a709d8c205fcfd04458658d09d380e3d2576 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sat, 14 Mar 2026 17:03:26 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/server.js b/server.js index 34f4b12..6cc084f 100644 --- a/server.js +++ b/server.js @@ -905,6 +905,77 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) { } } +// ========================================== +// 馃攼 OTP PARA CLIENTES (VERIFICACI脫N WHATSAPP) +// ========================================== + +// 1. Solicitar el c贸digo de 4 cifras +app.post("/public/auth/request-otp", async (req, res) => { + try { + const { phone, owner_id } = req.body; + if (!phone) return res.status(400).json({ ok: false }); + + const targetOwnerId = owner_id || 1; + const cleanPhone = phone.replace(/\D/g, ""); + + // Generar c贸digo de 4 cifras (ej: 4829) + const code = String(Math.floor(1000 + Math.random() * 9000)); + const hash = await bcrypt.hash(code, 10); + + // Guardamos el c贸digo (dejamos user_id nulo porque es un cliente externo) + await pool.query(` + INSERT INTO login_codes (phone, code_hash, purpose, expires_at) + VALUES ($1, $2, 'client_portal', NOW() + INTERVAL '15 minutes') + `, [cleanPhone, hash]); + + // Enviar el WhatsApp + const msg = `馃攼 Tu c贸digo de acceso para solicitar asistencia es: *${code}*\n\nSi no has solicitado este c贸digo, ignora este mensaje.`; + sendWhatsAppAuto("34" + cleanPhone, msg, `cliente_${targetOwnerId}`, false).catch(console.error); + + res.json({ ok: true }); + } catch(e) { + console.error("Error OTP Request:", e); + res.status(500).json({ ok: false }); + } +}); + +// 2. Verificar el c贸digo y comprobar si el cliente existe +app.post("/public/auth/verify-otp", async (req, res) => { + try { + const { phone, code, owner_id } = req.body; + const cleanPhone = phone.replace(/\D/g, ""); + const targetOwnerId = owner_id || 1; + + // Buscamos el 煤ltimo c贸digo v谩lido + const q = await pool.query(` + SELECT id, code_hash FROM login_codes + WHERE phone = $1 AND purpose = 'client_portal' AND consumed_at IS NULL AND expires_at > NOW() + ORDER BY created_at DESC LIMIT 1 + `, [cleanPhone]); + + if (q.rowCount === 0) return res.status(400).json({ ok: false, error: "C贸digo inv谩lido o caducado" }); + + // Comparamos el c贸digo que ha puesto el cliente con el de la BBDD + const valid = await bcrypt.compare(code, q.rows[0].code_hash); + if (!valid) return res.status(400).json({ ok: false, error: "C贸digo incorrecto" }); + + // Lo marcamos como usado + await pool.query("UPDATE login_codes SET consumed_at = NOW() WHERE id = $1", [q.rows[0].id]); + + // VERIFICAMOS SI EL CLIENTE YA EXISTE EN NUESTRA BASE DE DATOS + const qClient = await pool.query("SELECT id, full_name, addresses, portal_token FROM clients WHERE phone LIKE $1 AND owner_id = $2 LIMIT 1", [`%${cleanPhone}%`, targetOwnerId]); + + if (qClient.rowCount > 0) { + res.json({ ok: true, exists: true, client: qClient.rows[0] }); + } else { + res.json({ ok: true, exists: false }); + } + } catch(e) { + console.error("Error OTP Verify:", e); + res.status(500).json({ ok: false }); + } +}); + // ========================================== // 馃寪 EMBUDO P脷BLICO DE ENTRADA DE CLIENTES // ==========================================