diff --git a/src/PrintOne.ts b/src/PrintOne.ts index 9902748..4cdf9bd 100644 --- a/src/PrintOne.ts +++ b/src/PrintOne.ts @@ -32,6 +32,7 @@ import { ICsvOrder } from "~/models/_interfaces/ICsvOrder"; import { Batch, CreateBatch } from "~/models/Batch"; import { IBatch } from "~/models/_interfaces/IBatch"; import { BatchStatus } from "~/enums/BatchStatus"; +import * as crypto from "crypto"; export type RequestHandler = new ( token: string, @@ -518,4 +519,19 @@ export class PrintOne { (data) => new Batch(this.protected, data), ); } + + public validatedWebhook( + body: string, + headers: Record, + secret: string, + ): boolean { + const hmacHeader = headers["x-printone-hmac-sha256"]; + + const hmac = crypto + .createHmac("sha256", secret) + .update(body) + .digest("base64"); + + return hmac === hmacHeader; + } } diff --git a/test/PrintOne.spec.ts b/test/PrintOne.spec.ts index e4927b5..fda101b 100644 --- a/test/PrintOne.spec.ts +++ b/test/PrintOne.spec.ts @@ -1924,3 +1924,27 @@ describe("getBatches", function () { ); }); }); + +describe("validateWebhook", function () { + const body = + '{"data":{"id":"ord_QXitaPr7MumnHo2BYXuW9","companyId":"2bd4c679-3d59-4a6f-a815-a60424746f8d","templateId":"tmpl_AyDg3PxvP5ydyGq3kSFfj","finish":"GLOSSY","format":"POSTCARD_A5","mergeVariables":{},"recipient":{"name":"Your Name","address":"Street 1","postalCode":"1234 AB","city":"Amsterdam","country":"NL"},"definitiveCountryId":"NL","region":"NETHERLANDS","deliverySpeed":"FAST","isBillable":true,"status":"order_created","friendlyStatus":"Processing","errors":[],"metadata":{},"sendDate":"2024-01-01T00:00:00.000Z","createdAt":"2024-01-01T00:00:00.000Z","updatedAt":"2024-01-01T00:00:00.000Z","anonymizedAt":null,"csvOrderId":null},"created_at":"2024-06-03T13:14:46.501Z","event":"order_status_update"}'; + const headers = { + "x-printone-hmac-sha256": "blmkCA9eG2fajvgpHx/RBirRO8rA4wRGf6gr1/v+V0g=", + }; + + it("should return false if header does not match", () => { + expect( + client.validatedWebhook(body, headers, "invalid-header-secret"), + ).toBeFalse(); + }); + + it("should return if signature is valid", () => { + expect( + client.validatedWebhook( + body, + headers, + "0YFMgi5yzciEJV2HBL9wKWtNDnos8TaMOqtjSNErnDYWfign0JdW81vpmb6T62r4", + ), + ).toBeTrue(); + }); +});