Skip to content

Commit

Permalink
feat:octokit.verifyAndReceive() accepts raw string payload (#586)
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m authored Jun 17, 2021
1 parent 5145c91 commit e99dd37
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 6 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ webhooks.verify(eventPayload, signature);
eventPayload
</code>
<em>
(Object)
(Object or String)
</em>
</td>
<td>
Expand Down Expand Up @@ -260,7 +260,7 @@ webhooks.verifyAndReceive({ id, name, payload, signature });
payload
</code>
<em>
Object
Object or String
</em>
</td>
<td>
Expand Down
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
State,
WebhookError,
WebhookEventHandlerError,
EmitterWebhookEventWithStringPayloadAndSignature,
EmitterWebhookEventWithSignature,
} from "./types";

export { createNodeMiddleware } from "./middleware/node/index";
Expand All @@ -34,7 +36,9 @@ class Webhooks<TTransformed = unknown> {
) => void;
public receive: (event: EmitterWebhookEvent) => Promise<void>;
public verifyAndReceive: (
options: EmitterWebhookEvent & { signature: string }
options:
| EmitterWebhookEventWithStringPayloadAndSignature
| EmitterWebhookEventWithSignature
) => Promise<void>;

constructor(options: Options<TTransformed> & { secret: string }) {
Expand Down
11 changes: 11 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ export type EmitterWebhookEvent<
}
: BaseWebhookEvent<Extract<TEmitterEvent, WebhookEventName>>;

export type EmitterWebhookEventWithStringPayloadAndSignature = {
id: string;
name: EmitterWebhookEventName;
payload: string;
signature: string;
};

export type EmitterWebhookEventWithSignature = EmitterWebhookEvent & {
signature: string;
};

interface BaseWebhookEvent<TName extends WebhookEventName> {
id: string;
name: TName;
Expand Down
15 changes: 12 additions & 3 deletions src/verify-and-receive.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { verify } from "@octokit/webhooks-methods";

import { EmitterWebhookEvent, State } from "./types";
import {
EmitterWebhookEventWithStringPayloadAndSignature,
EmitterWebhookEventWithSignature,
State,
} from "./types";

export async function verifyAndReceive(
state: State & { secret: string },
event: EmitterWebhookEvent & { signature: string }
event:
| EmitterWebhookEventWithStringPayloadAndSignature
| EmitterWebhookEventWithSignature
): Promise<any> {
// verify will validate that the secret is not undefined
const matchesSignature = await verify(
Expand All @@ -26,6 +32,9 @@ export async function verifyAndReceive(
return state.eventHandler.receive({
id: event.id,
name: event.name,
payload: event.payload,
payload:
typeof event.payload === "string"
? JSON.parse(event.payload)
: event.payload,
});
}
34 changes: 34 additions & 0 deletions test/integration/webhooks.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { readFileSync } from "fs";

import { sign } from "@octokit/webhooks-methods";

import { Webhooks, EmitterWebhookEvent } from "../../src";

const pushEventPayloadString = readFileSync(
"test/fixtures/push-payload.json",
"utf-8"
);

describe("Webhooks", () => {
test("new Webhooks() without secret option", () => {
// @ts-expect-error
Expand All @@ -8,6 +17,31 @@ describe("Webhooks", () => {
);
});

test("webhooks.verify(payload, signature) with string payload", async () => {
const secret = "mysecret";
const webhooks = new Webhooks({ secret });

await webhooks.verify(
pushEventPayloadString,
await sign({ secret, algorithm: "sha256" }, pushEventPayloadString)
);
});

test("webhooks.verifyAndReceive({ ...event, signature }) with string payload", async () => {
const secret = "mysecret";
const webhooks = new Webhooks({ secret });

await webhooks.verifyAndReceive({
id: "1",
name: "push",
payload: pushEventPayloadString,
signature: await sign(
{ secret, algorithm: "sha256" },
pushEventPayloadString
),
});
});

test("webhooks.verifyAndReceive(event) with incorrect signature", async () => {
const webhooks = new Webhooks({ secret: "mysecret" });

Expand Down

0 comments on commit e99dd37

Please sign in to comment.