Skip to content

Commit

Permalink
feat: use verifyWithFallback to support secret rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
bismip committed Dec 5, 2024
1 parent 437be44 commit a4ae056
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ class Webhooks<TTransformed = unknown> {

const state: State & {
secret: string;
additionalSecrets?: undefined | string[];
eventHandler: EventHandler<TTransformed>;
} = {
eventHandler: createEventHandler(options),
secret: options.secret,
additionalSecrets: options.additionalSecrets,
hooks: {},
log: createLogger(options.log),
};
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface BaseWebhookEvent<TName extends WebhookEventName> {

export interface Options<TTransformed = unknown> {
secret?: string;
additionalSecrets?: undefined | string[];
transform?: TransformMethod<TTransformed>;
log?: Partial<Logger>;
}
Expand Down
5 changes: 3 additions & 2 deletions src/verify-and-receive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { verify } from "@octokit/webhooks-methods";
import { verifyWithFallback } from "@octokit/webhooks-methods";

import type {
EmitterWebhookEvent,
Expand All @@ -13,10 +13,11 @@ export async function verifyAndReceive(
event: EmitterWebhookEventWithStringPayloadAndSignature,
): Promise<void> {
// verify will validate that the secret is not undefined
const matchesSignature = await verify(
const matchesSignature = await verifyWithFallback(
state.secret,
event.payload,
event.signature,
state.additionalSecrets,
).catch(() => false);

if (!matchesSignature) {
Expand Down
41 changes: 41 additions & 0 deletions test/integration/node-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,47 @@ describe("createNodeMiddleware(webhooks)", () => {

server.close();
});

test("Additional secrets", async () => {
const signatureSha256AdditionalSecret = await sign(
"additionalSecret2",
pushEventPayload,
);

expect.assertions(3);

const webhooks = new Webhooks({
secret: "mySecret",
additionalSecrets: ["additionalSecret1", "additionalSecret2"],
});

webhooks.on("push", (event) => {
expect(event.id).toBe("123e4567-e89b-12d3-a456-426655440000");
});

const server = createServer(createNodeMiddleware(webhooks)).listen();

const { port } = server.address() as AddressInfo;

const response = await fetch(
`http://localhost:${port}/api/github/webhooks`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-GitHub-Delivery": "123e4567-e89b-12d3-a456-426655440000",
"X-GitHub-Event": "push",
"X-Hub-Signature-256": signatureSha256AdditionalSecret,
},
body: pushEventPayload,
},
);

expect(response.status).toEqual(200);
await expect(response.text()).resolves.toBe("ok\n");

server.close();
});
});

test("request.body is already an Object and has request.rawBody as Buffer (e.g. GCF)", async () => {
Expand Down

0 comments on commit a4ae056

Please sign in to comment.