diff --git a/apps/api/src/scripts/register-webhooks.ts b/apps/api/src/scripts/register-webhooks.ts index 76854e2..cd14127 100644 --- a/apps/api/src/scripts/register-webhooks.ts +++ b/apps/api/src/scripts/register-webhooks.ts @@ -3,7 +3,7 @@ import { env } from "../util"; const DOMAIN = "dev.api.bladeandbrawn.com"; -const PRINTFUL_WEBHOOK_URL = `http://${DOMAIN}/webhooks/printful`; +const PRINTFUL_WEBHOOK_URL = `http://${DOMAIN}/webhooks/printful?secret=${env.PRINTFUL_WEBHOOK_SECRET}`; const WEBFLOW_WEBHOOK_URL = `https://${DOMAIN}/webhooks/webflow`; function printError(err: unknown): never { diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index f1386f3..1baa7ca 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -322,8 +322,11 @@ export const app = new Elysia() ) // WEBHOOKS - .post("/webhooks/printful", async ({ body }) => { + .post("/webhooks/printful", async ({ body, query }) => { // https://webflow.com/integrations/printful + const verified = crypto.timingSafeEqual(Buffer.from(query.secret, "hex"), Buffer.from(env.PRINTFUL_WEBHOOK_SECRET, "hex")); + if (!verified) throw status(400, "Invalid secret"); + const payload = body as Printful.Webhook.EventPayload; switch (payload.type) { @@ -360,6 +363,9 @@ export const app = new Elysia() const shipment = payload.data.shipment; log.info({ wOrderId, carrier: shipment.carrier, tracking: shipment.tracking_number }, "printful webhook: package shipped"); + // TODO: possible to have multiple packages shipped + // order should NOT be immediately fulfulled in that case + await s.Commerce.Apparel.Orders.Queue.enqueue({ type: "apparel_order_fulfill", source: "printful", @@ -371,7 +377,7 @@ export const app = new Elysia() default: log.warn({ type: (payload as any).type }, "printful webhook: unhandled event type"); } - }) + }, { query: t.Object({ secret: t.String() }) }) .post("/webhooks/webflow", async ({ request, body }) => { if (!s.Commerce.Webflow.Util.verifyWebflowSignature(request, body)) throw status(400, "Invalid signature"); diff --git a/apps/api/src/util.ts b/apps/api/src/util.ts index b22b2cb..cb43db9 100644 --- a/apps/api/src/util.ts +++ b/apps/api/src/util.ts @@ -11,6 +11,7 @@ export const log = pino({ export const env = { PRINTFUL_AUTH: requireEnv("PRINTFUL_AUTH"), PRINTFUL_STORE_ID: requireEnv("PRINTFUL_STORE_ID"), + PRINTFUL_WEBHOOK_SECRET: requireEnv("PRINTFUL_WEBHOOK_SECRET"), WEBFLOW_SITE_ID: requireEnv("WEBFLOW_SITE_ID"), WEBFLOW_COLLECTION_SKUS_ID: requireEnv("WEBFLOW_COLLECTION_SKUS_ID"), WEBFLOW_COLLECTION_PRODUCTS_ID: requireEnv("WEBFLOW_COLLECTION_PRODUCTS_ID"),