Skip to content

Commit e99dd37

Browse files
authored
feat:octokit.verifyAndReceive() accepts raw string payload (#586)
1 parent 5145c91 commit e99dd37

File tree

5 files changed

+64
-6
lines changed

5 files changed

+64
-6
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ webhooks.verify(eventPayload, signature);
189189
eventPayload
190190
</code>
191191
<em>
192-
(Object)
192+
(Object or String)
193193
</em>
194194
</td>
195195
<td>
@@ -260,7 +260,7 @@ webhooks.verifyAndReceive({ id, name, payload, signature });
260260
payload
261261
</code>
262262
<em>
263-
Object
263+
Object or String
264264
</em>
265265
</td>
266266
<td>

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
State,
1212
WebhookError,
1313
WebhookEventHandlerError,
14+
EmitterWebhookEventWithStringPayloadAndSignature,
15+
EmitterWebhookEventWithSignature,
1416
} from "./types";
1517

1618
export { createNodeMiddleware } from "./middleware/node/index";
@@ -34,7 +36,9 @@ class Webhooks<TTransformed = unknown> {
3436
) => void;
3537
public receive: (event: EmitterWebhookEvent) => Promise<void>;
3638
public verifyAndReceive: (
37-
options: EmitterWebhookEvent & { signature: string }
39+
options:
40+
| EmitterWebhookEventWithStringPayloadAndSignature
41+
| EmitterWebhookEventWithSignature
3842
) => Promise<void>;
3943

4044
constructor(options: Options<TTransformed> & { secret: string }) {

src/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ export type EmitterWebhookEvent<
1515
}
1616
: BaseWebhookEvent<Extract<TEmitterEvent, WebhookEventName>>;
1717

18+
export type EmitterWebhookEventWithStringPayloadAndSignature = {
19+
id: string;
20+
name: EmitterWebhookEventName;
21+
payload: string;
22+
signature: string;
23+
};
24+
25+
export type EmitterWebhookEventWithSignature = EmitterWebhookEvent & {
26+
signature: string;
27+
};
28+
1829
interface BaseWebhookEvent<TName extends WebhookEventName> {
1930
id: string;
2031
name: TName;

src/verify-and-receive.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { verify } from "@octokit/webhooks-methods";
22

3-
import { EmitterWebhookEvent, State } from "./types";
3+
import {
4+
EmitterWebhookEventWithStringPayloadAndSignature,
5+
EmitterWebhookEventWithSignature,
6+
State,
7+
} from "./types";
48

59
export async function verifyAndReceive(
610
state: State & { secret: string },
7-
event: EmitterWebhookEvent & { signature: string }
11+
event:
12+
| EmitterWebhookEventWithStringPayloadAndSignature
13+
| EmitterWebhookEventWithSignature
814
): Promise<any> {
915
// verify will validate that the secret is not undefined
1016
const matchesSignature = await verify(
@@ -26,6 +32,9 @@ export async function verifyAndReceive(
2632
return state.eventHandler.receive({
2733
id: event.id,
2834
name: event.name,
29-
payload: event.payload,
35+
payload:
36+
typeof event.payload === "string"
37+
? JSON.parse(event.payload)
38+
: event.payload,
3039
});
3140
}

test/integration/webhooks.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1+
import { readFileSync } from "fs";
2+
3+
import { sign } from "@octokit/webhooks-methods";
4+
15
import { Webhooks, EmitterWebhookEvent } from "../../src";
26

7+
const pushEventPayloadString = readFileSync(
8+
"test/fixtures/push-payload.json",
9+
"utf-8"
10+
);
11+
312
describe("Webhooks", () => {
413
test("new Webhooks() without secret option", () => {
514
// @ts-expect-error
@@ -8,6 +17,31 @@ describe("Webhooks", () => {
817
);
918
});
1019

20+
test("webhooks.verify(payload, signature) with string payload", async () => {
21+
const secret = "mysecret";
22+
const webhooks = new Webhooks({ secret });
23+
24+
await webhooks.verify(
25+
pushEventPayloadString,
26+
await sign({ secret, algorithm: "sha256" }, pushEventPayloadString)
27+
);
28+
});
29+
30+
test("webhooks.verifyAndReceive({ ...event, signature }) with string payload", async () => {
31+
const secret = "mysecret";
32+
const webhooks = new Webhooks({ secret });
33+
34+
await webhooks.verifyAndReceive({
35+
id: "1",
36+
name: "push",
37+
payload: pushEventPayloadString,
38+
signature: await sign(
39+
{ secret, algorithm: "sha256" },
40+
pushEventPayloadString
41+
),
42+
});
43+
});
44+
1145
test("webhooks.verifyAndReceive(event) with incorrect signature", async () => {
1246
const webhooks = new Webhooks({ secret: "mysecret" });
1347

0 commit comments

Comments
 (0)