| import fs from "fs"; |
| import express from "express"; |
| import * as wppconnect from '@wppconnect-team/wppconnect'; |
| import path from "path"; |
| import { fileURLToPath } from 'url'; |
|
|
| const __filename = fileURLToPath(import.meta.url); |
| const __dirname = path.dirname(__filename); |
|
|
| let wppClient = null; |
| let currentStatus = 'DISCONNECTED'; |
| let qrCodeBase64 = ''; |
| let logs = []; |
|
|
| function addLog(msg) { |
| const timestamp = new Date().toLocaleTimeString(); |
| const fullMsg = `[${timestamp}] ${msg}`; |
| logs.push(fullMsg); |
| if (logs.length > 100) logs.shift(); |
| console.log(fullMsg); |
| } |
|
|
| const app = express(); |
| const PORT = process.env.PORT || 7860; |
|
|
| app.use(express.json()); |
|
|
| |
| function isValidPasskey(provided) { |
| const envPasskey = process.env.PASSKEY; |
| if (!envPasskey) return true; |
| return provided === envPasskey || provided === `Bearer ${envPasskey}`; |
| } |
|
|
| |
| function checkPasskey(req, res, next) { |
| const provided = req.headers['x-passkey'] || req.headers['authorization'] || req.query.passkey; |
| if (isValidPasskey(provided)) return next(); |
| res.status(401).json({ error: 'Unauthorized' }); |
| } |
|
|
| app.get("/health", (req, res) => res.send("OK")); |
|
|
| app.post('/api/login', (req, res) => { |
| const { passkey } = req.body; |
| if (isValidPasskey(passkey)) { |
| addLog("Successful login attempt."); |
| res.json({ success: true }); |
| } else { |
| addLog(`Failed login attempt.`); |
| res.status(401).json({ success: false, error: 'Invalid passkey' }); |
| } |
| }); |
|
|
| app.get("/api/status", checkPasskey, (req, res) => { |
| res.json({ status: currentStatus, qrCode: qrCodeBase64, logs }); |
| }); |
|
|
| app.get("/api/groups", checkPasskey, async (req, res) => { |
| if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); |
| try { |
| const chats = await wppClient.listChats(); |
| const groups = chats.filter(chat => chat.isGroup); |
| res.json({ success: true, groups }); |
| } catch (error) { |
| res.status(500).json({ error: error.message }); |
| } |
| }); |
|
|
| app.post("/api/groups/join", checkPasskey, async (req, res) => { |
| if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); |
| const { inviteCode } = req.body; |
| if (!inviteCode) return res.status(400).json({ error: 'Invite code required' }); |
| try { |
| addLog(`Joining group with invite code...`); |
| const result = await wppClient.joinGroup(inviteCode); |
| addLog("Joined group successfully!"); |
| res.json({ success: true, result }); |
| } catch (error) { |
| addLog(`Join group error: ${error.message}`); |
| res.status(500).json({ error: error.message }); |
| } |
| }); |
|
|
| app.post('/api/start', checkPasskey, async (req, res) => { |
| if (currentStatus === 'CONNECTED' || currentStatus === 'INITIALIZING') { |
| return res.json({ success: true, status: currentStatus }); |
| } |
|
|
| currentStatus = 'INITIALIZING'; |
| qrCodeBase64 = ''; |
| addLog('Initializing WPPConnect session...'); |
| res.json({ success: true }); |
|
|
| try { |
| const sessionPath = path.join(__dirname, 'tokens', 'gradio-session'); |
| if (fs.existsSync(sessionPath)) { |
| try { |
| fs.rmSync(sessionPath, { recursive: true, force: true }); |
| addLog("Cleared stale session tokens."); |
| } catch (e) { |
| addLog(`Warning: Could not clear session path: ${e.message}`); |
| } |
| } |
|
|
| wppClient = await wppconnect.create({ |
| session: 'gradio-session', |
| autoClose: 0, |
| updatesLog: true, |
| catchQR: (base64Qr) => { |
| currentStatus = 'QR_CODE'; |
| qrCodeBase64 = base64Qr; |
| addLog("QR Code generated."); |
| }, |
| statusFind: (statusSession) => { |
| addLog(`Session Status: ${statusSession}`); |
| if (['isLogged', 'inChat', 'qrReadSuccess', 'chatsAvailable'].includes(statusSession)) { |
| currentStatus = 'CONNECTED'; |
| qrCodeBase64 = ''; |
| addLog("WhatsApp connection established."); |
| } |
| }, |
| headless: true, |
| puppeteerOptions: { |
| executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium', |
| args: [ |
| '--no-sandbox', |
| '--disable-setuid-sandbox', |
| '--disable-dev-shm-usage', |
| '--disable-gpu', |
| '--no-zygote' |
| ] |
| } |
| }); |
| |
| |
| wppClient.onInterfaceChange((state) => { |
| addLog(`Interface state: ${state.display || state.mode}`); |
| if (state.display === 'MAIN') { |
| currentStatus = 'CONNECTED'; |
| qrCodeBase64 = ''; |
| addLog("WhatsApp reached MAIN interface."); |
| } |
| }); |
|
|
| const isLogged = await wppClient.isLoggedIn(); |
| if (isLogged) { |
| currentStatus = 'CONNECTED'; |
| addLog("Validated: User is logged in."); |
| } |
|
|
| } catch (error) { |
| addLog(`WPPConnect Error: ${error.message}`); |
| currentStatus = 'ERROR'; |
| wppClient = null; |
| } |
| }); |
|
|
| app.post('/api/send', checkPasskey, async (req, res) => { |
| if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); |
| const { phone, message, isGroup, poll } = req.body; |
| try { |
| let recipient = phone; |
| if (!phone.includes('@')) recipient = isGroup ? `${phone}@g.us` : `${phone}@c.us`; |
| |
| if (poll && poll.name && poll.options) { |
| addLog(`Sending poll to ${recipient}...`); |
| const result = await wppClient.sendPollMessage(recipient, poll.name, poll.options, { |
| selectableCount: poll.selectableCount || 1 |
| }); |
| addLog("Poll sent!"); |
| return res.json({ success: true, result }); |
| } |
| |
| addLog(`Sending message to ${recipient}...`); |
| const result = await wppClient.sendText(recipient, message); |
| addLog("Message sent!"); |
| res.json({ success: true, result }); |
| } catch (error) { |
| addLog(`Send Error: ${error.message}`); |
| res.status(500).json({ error: error.message }); |
| } |
| }); |
|
|
| const distPath = path.join(__dirname, 'dist'); |
| if (fs.existsSync(distPath)) { |
| app.use(express.static(distPath)); |
| app.get('*', (req, res) => { |
| if (req.path.startsWith('/api/')) return res.status(404).json({ error: 'API route not found' }); |
| res.sendFile(path.join(distPath, 'index.html')); |
| }); |
| } |
|
|
| app.listen(PORT, "0.0.0.0", () => { |
| console.log(`Server running on port ${PORT}`); |
| }); |
|
|