const fs = require('fs'); const path = require('path'); const dotenv = require('dotenv'); // Find .env file identically to how PHP bootstrap does it const envPaths = [ path.join(__dirname, '.env'), path.join(__dirname, '../.env'), path.join(__dirname, '../backend/.env'), path.join(__dirname, '../../../.env') ]; for (const p of envPaths) { if (fs.existsSync(p)) { dotenv.config({ path: p }); console.log(`Loaded environment from ${p}`); break; } } const express = require('express'); const cors = require('cors'); const { startSession, disconnectSession, sendMessage, getActiveSessions, checkContact } = require('./baileys-client'); const app = express(); app.use(cors()); app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ limit: '50mb', extended: true })); const PORT = process.env.PORT || 3722; // Health check endpoint (Public) app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'Nabeh WhatsApp Gateway' }); }); // Security Middleware: Protect all /api/ routes app.use('/api', (req, res, next) => { const secret = req.header('X-Webhook-Secret'); if (!process.env.WEBHOOK_SECRET || secret !== process.env.WEBHOOK_SECRET) { return res.status(403).json({ error: 'Unauthorized gateway access' }); } next(); }); // Start or retrieve a session app.post('/api/sessions/start', async (req, res) => { const { session_key, webhook_url } = req.body; if (!session_key || !webhook_url) { return res.status(400).json({ error: 'Missing session_key or webhook_url' }); } try { await startSession(session_key, webhook_url); res.json({ status: 'success', message: 'Session started or retrieved' }); } catch (err) { console.error(`Error starting session ${session_key}:`, err); res.status(500).json({ error: 'Failed to start session' }); } }); // Disconnect and remove a session (e.g., when banned or logged out) app.post('/api/sessions/disconnect', async (req, res) => { const { session_key } = req.body; if (!session_key) { return res.status(400).json({ error: 'Missing session_key' }); } try { await disconnectSession(session_key); res.json({ status: 'success', message: 'Session disconnected and cleaned up' }); } catch (err) { console.error(`Error disconnecting session ${session_key}:`, err); res.status(500).json({ error: 'Failed to disconnect session' }); } }); // Get list of active session keys in memory app.get('/api/sessions/active', (req, res) => { res.json({ status: 'success', active_sessions: getActiveSessions() }); }); // Check if contact is on WhatsApp app.post('/api/contacts/check', async (req, res) => { const { session_key, phone } = req.body; if (!session_key || !phone) { return res.status(400).json({ error: 'Missing session_key or phone' }); } try { const result = await checkContact(session_key, phone); res.json({ status: 'success', data: result }); } catch (err) { console.error(`Error checking contact ${phone} via ${session_key}:`, err); res.status(500).json({ error: err.message || 'Failed to check contact' }); } }); // Send outbound message app.post('/api/messages/send', async (req, res) => { const { session_key, phone, message, media_url, audio, mimetype, image } = req.body; if (!session_key || !phone) { return res.status(400).json({ error: 'Missing session_key or phone' }); } if (!message && !audio && !media_url && !image) { return res.status(400).json({ error: 'Missing message, audio, media_url, or image' }); } try { const result = await sendMessage(session_key, phone, message, media_url, audio, mimetype, image); res.json({ status: 'success', data: result }); } catch (err) { console.error(`Error sending message via ${session_key} to ${phone}:`, err); res.status(500).json({ error: err.message || 'Failed to send message' }); } }); app.listen(PORT, () => { console.log(`🚀 Nabeh WhatsApp Gateway running on port ${PORT}`); });