Add shared printful webhook secret for authentication
This commit is contained in:
@@ -3,7 +3,7 @@ import { env } from "../util";
|
|||||||
|
|
||||||
const DOMAIN = "dev.api.bladeandbrawn.com";
|
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`;
|
const WEBFLOW_WEBHOOK_URL = `https://${DOMAIN}/webhooks/webflow`;
|
||||||
|
|
||||||
function printError(err: unknown): never {
|
function printError(err: unknown): never {
|
||||||
|
|||||||
@@ -322,8 +322,11 @@ export const app = new Elysia()
|
|||||||
)
|
)
|
||||||
|
|
||||||
// WEBHOOKS
|
// WEBHOOKS
|
||||||
.post("/webhooks/printful", async ({ body }) => {
|
.post("/webhooks/printful", async ({ body, query }) => {
|
||||||
// https://webflow.com/integrations/printful
|
// 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;
|
const payload = body as Printful.Webhook.EventPayload;
|
||||||
|
|
||||||
switch (payload.type) {
|
switch (payload.type) {
|
||||||
@@ -360,6 +363,9 @@ export const app = new Elysia()
|
|||||||
const shipment = payload.data.shipment;
|
const shipment = payload.data.shipment;
|
||||||
log.info({ wOrderId, carrier: shipment.carrier, tracking: shipment.tracking_number }, "printful webhook: package shipped");
|
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({
|
await s.Commerce.Apparel.Orders.Queue.enqueue({
|
||||||
type: "apparel_order_fulfill",
|
type: "apparel_order_fulfill",
|
||||||
source: "printful",
|
source: "printful",
|
||||||
@@ -371,7 +377,7 @@ export const app = new Elysia()
|
|||||||
default:
|
default:
|
||||||
log.warn({ type: (payload as any).type }, "printful webhook: unhandled event type");
|
log.warn({ type: (payload as any).type }, "printful webhook: unhandled event type");
|
||||||
}
|
}
|
||||||
})
|
}, { query: t.Object({ secret: t.String() }) })
|
||||||
.post("/webhooks/webflow", async ({ request, body }) => {
|
.post("/webhooks/webflow", async ({ request, body }) => {
|
||||||
if (!s.Commerce.Webflow.Util.verifyWebflowSignature(request, body))
|
if (!s.Commerce.Webflow.Util.verifyWebflowSignature(request, body))
|
||||||
throw status(400, "Invalid signature");
|
throw status(400, "Invalid signature");
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const log = pino({
|
|||||||
export const env = {
|
export const env = {
|
||||||
PRINTFUL_AUTH: requireEnv("PRINTFUL_AUTH"),
|
PRINTFUL_AUTH: requireEnv("PRINTFUL_AUTH"),
|
||||||
PRINTFUL_STORE_ID: requireEnv("PRINTFUL_STORE_ID"),
|
PRINTFUL_STORE_ID: requireEnv("PRINTFUL_STORE_ID"),
|
||||||
|
PRINTFUL_WEBHOOK_SECRET: requireEnv("PRINTFUL_WEBHOOK_SECRET"),
|
||||||
WEBFLOW_SITE_ID: requireEnv("WEBFLOW_SITE_ID"),
|
WEBFLOW_SITE_ID: requireEnv("WEBFLOW_SITE_ID"),
|
||||||
WEBFLOW_COLLECTION_SKUS_ID: requireEnv("WEBFLOW_COLLECTION_SKUS_ID"),
|
WEBFLOW_COLLECTION_SKUS_ID: requireEnv("WEBFLOW_COLLECTION_SKUS_ID"),
|
||||||
WEBFLOW_COLLECTION_PRODUCTS_ID: requireEnv("WEBFLOW_COLLECTION_PRODUCTS_ID"),
|
WEBFLOW_COLLECTION_PRODUCTS_ID: requireEnv("WEBFLOW_COLLECTION_PRODUCTS_ID"),
|
||||||
|
|||||||
Reference in New Issue
Block a user