const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const parts = signature.split(',');
const timestamp = parts[0].split('=')[1];
const receivedSig = parts[1].split('=')[1];
// Check timestamp (reject if > 5 minutes old)
const now = Math.floor(Date.now() / 1000);
if (now - parseInt(timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}
// Compute expected signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSig = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Timing-safe comparison
if (!crypto.timingSafeEqual(
Buffer.from(receivedSig),
Buffer.from(expectedSig)
)) {
throw new Error('Invalid webhook signature');
}
return JSON.parse(payload);
}
// Express.js handler
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
try {
const event = verifyWebhookSignature(
req.body.toString(),
req.headers['x-baclique-signature'],
process.env.WEBHOOK_SECRET
);
switch (event.type) {
case 'conversion.created':
console.log('New conversion:', event.data.id);
break;
case 'conversion.approved':
console.log('Conversion approved:', event.data.id);
break;
}
res.status(200).send('OK');
} catch (err) {
console.error('Webhook error:', err.message);
res.status(400).send('Invalid signature');
}
});