production secret added
This commit is contained in:
@@ -7,14 +7,14 @@ initializeApp();
|
||||
const db = getFirestore();
|
||||
|
||||
/**
|
||||
* Shopdm Pay Webhook Handler
|
||||
* Shopdm Pay Webhook Handler (v2)
|
||||
*
|
||||
* Receives payment.successful events from Shopdm Pay.
|
||||
* Matches the invoice_id to a pending donation and creates
|
||||
* a confirmed donor record.
|
||||
*/
|
||||
exports.shopdmPayWebhook = onRequest(
|
||||
{ secrets: ["SHOPDM_MERCHANT_SECRET_DEV"] },
|
||||
{ secrets: ["SHOPDM_MERCHANT_SECRET", "SHOPDM_MERCHANT_SECRET_DEV"], invoker: "public" },
|
||||
async (req, res) => {
|
||||
// Only accept POST requests
|
||||
if (req.method !== "POST") {
|
||||
@@ -24,8 +24,7 @@ exports.shopdmPayWebhook = onRequest(
|
||||
|
||||
const payload = req.body;
|
||||
|
||||
// Verify webhook signature
|
||||
// Supports both dev and prod secrets
|
||||
// Verify webhook signature using sorted keys + HMAC-SHA256 (per Shopdm Pay docs)
|
||||
const secrets = [
|
||||
process.env.SHOPDM_MERCHANT_SECRET,
|
||||
process.env.SHOPDM_MERCHANT_SECRET_DEV,
|
||||
@@ -39,10 +38,7 @@ exports.shopdmPayWebhook = onRequest(
|
||||
return;
|
||||
}
|
||||
|
||||
const sortedPayload = JSON.stringify(
|
||||
payload,
|
||||
Object.keys(payload).sort()
|
||||
);
|
||||
const sortedPayload = JSON.stringify(payload, Object.keys(payload).sort());
|
||||
|
||||
const isValid = secrets.some((secret) => {
|
||||
const expected = crypto
|
||||
@@ -57,14 +53,21 @@ exports.shopdmPayWebhook = onRequest(
|
||||
res.status(401).send("Unauthorized");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Webhook signature verified successfully");
|
||||
}
|
||||
|
||||
// Only process successful payments
|
||||
if (payload.event !== "payment.successful") {
|
||||
if (payload.event !== "payment.successful" && payload.event !== "payment.success") {
|
||||
res.status(200).send("Event ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine environment from the live flag in the payload
|
||||
const isLive = payload.live === true;
|
||||
const webhookEnv = isLive ? "production" : "dev";
|
||||
console.log(`Webhook environment: ${webhookEnv} (live=${payload.live})`);
|
||||
|
||||
const invoiceId = payload.metadata?.invoice_id;
|
||||
if (!invoiceId) {
|
||||
console.log("No invoice_id in webhook payload, skipping donor creation");
|
||||
@@ -85,6 +88,16 @@ exports.shopdmPayWebhook = onRequest(
|
||||
|
||||
const pending = pendingDoc.data();
|
||||
|
||||
// Ensure the webhook environment matches the pending donation environment
|
||||
const pendingEnv = pending.env || "production";
|
||||
if (pendingEnv !== webhookEnv) {
|
||||
console.warn(
|
||||
`Environment mismatch: pending donation is ${pendingEnv} but webhook is ${webhookEnv}. Skipping.`
|
||||
);
|
||||
res.status(200).send("OK - environment mismatch");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already processed (idempotency)
|
||||
if (pending.status === "confirmed") {
|
||||
console.log(`Donation ${invoiceId} already confirmed, skipping`);
|
||||
@@ -103,6 +116,7 @@ exports.shopdmPayWebhook = onRequest(
|
||||
message: pending.message || "",
|
||||
anonymous: !!pending.anonymous,
|
||||
status: "confirmed",
|
||||
env: webhookEnv,
|
||||
pendingDonationId: invoiceId,
|
||||
paymentId: payload.data?.object_id || "",
|
||||
date: FieldValue.serverTimestamp(),
|
||||
|
||||
Reference in New Issue
Block a user