Локалізовано за допомогою ШІ

Перевірка підпису

import crypto from 'crypto';

function verifyWebhookSignature(rawBody, signature, timestamp, secret) {
  const signedPayload = `${timestamp}.${rawBody}`;
  const computed = crypto
    .createHmac('sha256', secret)
    .update(signedPayload, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computed, 'hex'),
    Buffer.from(signature, 'hex')
  );
}

// У вашому обробнику webhook'а:
const rawBody = req.body; // необроблене тіло запиту як рядок
const signature = req.headers['x-emailit-signature'];
const timestamp = req.headers['x-emailit-timestamp'];
const secret = process.env.WEBHOOK_SIGNING_SECRET;

// Захист від атак повторного відтворення (толерантність 5 хвилин)
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > 300) {
  return res.status(401).send('Запит занадто старий');
}

if (!verifyWebhookSignature(rawBody, signature, timestamp, secret)) {
  return res.status(401).send('Недійсний підпис');
}