← back to Dw Signup Fulfillment
lib/webhook.js
30 lines
'use strict';
// Shopify webhook HMAC verification. Shopify signs the RAW request body with the
// app's webhook secret (SHA-256, base64) and sends it in X-Shopify-Hmac-Sha256.
// We MUST verify against the raw bytes — parsed/re-stringified JSON will not match.
const crypto = require('crypto');
const config = require('./config');
// verify(rawBody: Buffer|string, hmacHeader: string) -> boolean
function verify(rawBody, hmacHeader) {
if (!config.SHOPIFY_WEBHOOK_SECRET) return false;
if (!hmacHeader) return false;
const digest = crypto
.createHmac('sha256', config.SHOPIFY_WEBHOOK_SECRET)
.update(Buffer.isBuffer(rawBody) ? rawBody : Buffer.from(rawBody, 'utf8'))
.digest('base64');
const a = Buffer.from(digest);
const b = Buffer.from(hmacHeader);
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
// Helper for tests / go-live smoke: compute the header a given secret would produce.
function sign(rawBody, secret) {
return crypto.createHmac('sha256', secret)
.update(Buffer.isBuffer(rawBody) ? rawBody : Buffer.from(rawBody, 'utf8'))
.digest('base64');
}
module.exports = { verify, sign };