const express = require('express');
const crypto = require('crypto');
const app = express();
// Middleware to parse JSON bodies
app.use(express.json());
// Middleware to validate incoming webhook requests
const validateWebhook = (req, res, next) => {
// Extract signature and timestamp headers from the request
const signature = req.headers['conduit-signature'];
const timestamp = req.headers['conduit-signature-timestamp'];
// Reject request if headers are missing
if (!signature || !timestamp) {
console.error('Missing signature headers');
return res.status(401).send({ error: 'Missing signature headers' });
}
// Get your webhook secret from environment variables
const secret = process.env.WEBHOOK_SECRET;
if (!secret) {
console.error('Webhook secret is not configured');
return res.status(500).send({ error: 'Server configuration error' });
}
// Convert request body to string for signing
const payload = JSON.stringify(req.body);
// Create the string to sign: "<timestamp>.<payload>"
const stringToSign = `${timestamp}.${payload}`;
try {
// Compute HMAC SHA256 hash using your secret
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(stringToSign)
.digest('hex');
// Compare expected signature with the one sent by Conduit
if (expectedSignature !== signature) {
console.error('Invalid signature');
return res.status(401).send({ error: 'Invalid signature' });
}
// Signature verified — proceed to next middleware or route handler
next();
} catch (error) {
console.error('Webhook validation error:', error);
return res.status(401).send({ error: 'Webhook validation failed' });
}
};
// Webhook endpoint with validation middleware applied
app.post('/', validateWebhook, (req, res) => {
res.status(200).send({ message: 'Webhook received' });
});
// Start server
const PORT = process.env.PORT || 9876;
app.listen(PORT, () => {
console.log(`Webhook client listening on port ${PORT}`);
});