diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8ec2088..406d457d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,7 +5,7 @@ name: Release - main - next - beta - - v*.x + - "+([0-9]).x" jobs: release: name: release diff --git a/src/verify-and-receive.ts b/src/verify-and-receive.ts index 4b264c0e..b45bb2cd 100644 --- a/src/verify-and-receive.ts +++ b/src/verify-and-receive.ts @@ -20,7 +20,7 @@ export async function verifyAndReceive( ? toNormalizedJsonString(event.payload) : event.payload, event.signature - ); + ).catch(() => false); if (!matchesSignature) { const error = new Error( diff --git a/test/integration/node-middleware.test.ts b/test/integration/node-middleware.test.ts index 4ecb70b6..9f9e9d4f 100644 --- a/test/integration/node-middleware.test.ts +++ b/test/integration/node-middleware.test.ts @@ -571,4 +571,51 @@ describe("createNodeMiddleware(webhooks)", () => { server.close(); }); + + test("Handles invalid signature", async () => { + expect.assertions(3); + + const webhooks = new Webhooks({ + secret: "mySecret", + }); + + webhooks.onError((error) => { + expect(error.message).toContain( + "signature does not match event payload and secret" + ); + }); + + const log = { + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + const middleware = createNodeMiddleware(webhooks, { log }); + const server = createServer(middleware).listen(); + + // @ts-expect-error complains about { port } although it's included in returned AddressInfo interface + const { port } = server.address(); + + const response = await fetch( + `http://localhost:${port}/api/github/webhooks`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-GitHub-Delivery": "1", + "X-GitHub-Event": "push", + "X-Hub-Signature-256": "", + }, + body: pushEventPayload, + } + ); + + expect(response.status).toEqual(400); + await expect(response.text()).resolves.toBe( + '{"error":"Error: [@octokit/webhooks] signature does not match event payload and secret"}' + ); + + server.close(); + }); });