require("dotenv").config(); const express = require("express"); const crypto = require("crypto"); const router = express.Router(); router.use(express.raw({ type: "*/*" })); const SHOPIFY_API_SECRET = process.env.SHOPIFY_API_SECRET; function verifyHmac(rawBody, hmacHeader) { if (!SHOPIFY_API_SECRET || !hmacHeader || !rawBody) { return false; } const digest = crypto .createHmac("sha256", SHOPIFY_API_SECRET) .update(rawBody) .digest("base64"); const generated = Buffer.from(digest, "utf8"); const received = Buffer.from(hmacHeader, "utf8"); if (generated.length !== received.length) { return false; } return crypto.timingSafeEqual(generated, received); } function parseJsonSafe(buf) { try { return JSON.parse(buf.toString("utf8")); } catch { return null; } } function handleWebhook(req, res, topicName) { const hmacHeader = req.header("x-shopify-hmac-sha256"); const shop = req.header("x-shopify-shop-domain"); const topic = req.header("x-shopify-topic") || topicName; if (!verifyHmac(req.body, hmacHeader)) { return res.status(401).send("Invalid HMAC"); } const payload = parseJsonSafe(req.body) || {}; console.log(`[WEBHOOK:${topic}] shop=${shop}`, payload); return res.status(200).json({ status: "ok", topic, shop, received: payload }); } router.post("/customers/data_request", (req, res) => handleWebhook(req, res, "customers/data_request")); router.post("/customers/redact", (req, res) => handleWebhook(req, res, "customers/redact")); router.post("/shop/redact", (req, res) => handleWebhook(req, res, "shop/redact")); module.exports = router;