// routes/twilioCallTest.js // Twilio voice + status webhooks for /calltest. import express from 'express'; import { validateTwilioSignature } from '../integrations/twilio/client.js'; import { logger } from '../utils/logger.js'; import { getWebhookBaseUrl, resolveCallTestWebhookUrl, } from '../services/callTest/config.js'; import { handleStatusCallback, handleVoiceWebhook, isCallTestConfigured, } from '../services/callTest/callTestService.js'; const router = express.Router(); function verifyTwilio(req, res, next) { if (!isCallTestConfigured()) { return res.status(503).send('Call test not configured'); } const signature = req.get('X-Twilio-Signature') || req.get('x-twilio-signature'); const url = resolveCallTestWebhookUrl(req); const params = req.body || {}; if (!url) { return next(); } try { if (!validateTwilioSignature(signature, url, params)) { logger( 'calltest:webhook', `Invalid Twilio signature for ${req.originalUrl} ` + `(validated as ${url}, base=${getWebhookBaseUrl()}, bodyKeys=${Object.keys(params).length})`, 'warn', ); return res.status(403).send('Forbidden'); } } catch (err) { logger('calltest:webhook', `Signature check error: ${err.message}`, 'error'); return res.status(503).send('Not configured'); } return next(); } router.post('/twilio/calltest/voice', verifyTwilio, (req, res) => { const testId = req.query.testId; const mode = req.query.mode === 'store' ? 'store' : 'dial'; const step = String(req.query.step || '').trim(); if (!testId || !step) { return res.status(400).type('text/xml').send( 'Missing test parameters.', ); } logger('calltest:webhook', `Voice testId=${testId} mode=${mode} step=${step}`, 'info'); const twiml = handleVoiceWebhook(testId, mode, step); res.type('text/xml').send(twiml); }); router.post('/twilio/calltest/status', verifyTwilio, async (req, res) => { const testId = req.query.testId; if (!testId) { return res.status(400).send('Missing testId'); } logger( 'calltest:webhook', `Status testId=${testId} CallStatus=${req.body?.CallStatus} CallSid=${req.body?.CallSid}`, 'info', ); try { await handleStatusCallback(testId, req.body || {}); res.status(200).send('OK'); } catch (err) { logger('calltest:webhook', `Status handler error: ${err.message}`, 'error'); res.status(500).send('Error'); } }); export default router;