const crypto = require('crypto');
const express = require('express');
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
function verifySignature(payload, signature, timestamp, secret, tolerance = 300) {
if (!signature || !timestamp) return false;
const timestampValue = Number(timestamp);
if (!Number.isInteger(timestampValue)) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - timestampValue) > tolerance) return false;
const signedPayload = Buffer.concat([
Buffer.from(`${timestamp}.`, 'utf8'),
payload,
]);
const expected = `sha256=${crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex')}`;
const providedBuffer = Buffer.from(signature, 'utf8');
const expectedBuffer = Buffer.from(expected, 'utf8');
return providedBuffer.length === expectedBuffer.length
&& crypto.timingSafeEqual(providedBuffer, expectedBuffer);
}
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.header('X-Webhook-Signature');
const timestamp = req.header('X-Webhook-Timestamp');
if (!verifySignature(req.body, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(req.body.toString('utf8'));
processEvent(event);
return res.status(200).send('OK');
});