import crypto from 'node:crypto';
function verifyWaspySignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((p) => p.split('=')),
);
const t = parts.t;
const v1 = parts.v1;
if (!t || !v1) return false;
// Replay protection: reject if older than 5 minutes
const age = Math.abs(Math.floor(Date.now() / 1000) - parseInt(t, 10));
if (age > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
// Express ejemplo (con express.raw para preservar bytes exactos)
app.post('/webhook/waspy',
express.raw({ type: 'application/json' }),
(req, res) => {
const ok = verifyWaspySignature(
req.body.toString(),
req.header('X-Waspy-Signature') || '',
process.env.WASPY_WEBHOOK_SECRET,
);
if (!ok) return res.status(401).end();
const event = JSON.parse(req.body.toString());
// ... procesar event
res.status(200).end();
},
);