const crypto = require('crypto');
const express = require('express');
function timingSafeEqualHex(left, right) {
const a = Buffer.from(String(left || ''), 'hex');
const b = Buffer.from(String(right || ''), 'hex');
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
function computeSignature(secret, timestampMs, rawBody) {
const signed = `${timestampMs}.${rawBody}`;
return crypto.createHmac('sha256', secret).update(signed).digest('hex');
}
const app = express();
app.post('/webhooks/pepay', express.raw({ type: 'application/json' }), (req, res) => {
const timestampMs = req.get('X-Pepay-Timestamp');
const signature = req.get('X-Pepay-Signature');
const signaturePrevious = req.get('X-Pepay-Signature-Previous');
const rawBody = req.body.toString('utf8');
const nowMs = Date.now();
if (Math.abs(nowMs - Number(timestampMs)) > 5 * 60 * 1000) {
return res.status(400).send('timestamp_out_of_range');
}
const expected = computeSignature(process.env.PEPAY_WEBHOOK_SECRET, timestampMs, rawBody);
const expectedPrevious = process.env.PEPAY_WEBHOOK_SECRET_PREVIOUS
? computeSignature(process.env.PEPAY_WEBHOOK_SECRET_PREVIOUS, timestampMs, rawBody)
: null;
const ok =
timingSafeEqualHex(signature, expected) ||
(expectedPrevious && timingSafeEqualHex(signaturePrevious, expectedPrevious));
if (!ok) return res.status(400).send('invalid_signature');
return res.status(200).send('ok');
});