Skip to content

Commit b0fa998

Browse files
committed
task handler
1 parent 3009807 commit b0fa998

File tree

1 file changed

+58
-2
lines changed

1 file changed

+58
-2
lines changed

integrations/github/src/index.ts

+58-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import {
2121
import { configBlock } from './components';
2222
import { getGitHubAppJWT } from './provider';
2323
import { triggerExport, updateCommitWithPreviewLinks } from './sync';
24-
import type { GithubRuntimeContext } from './types';
25-
import { BRANCH_REF_PREFIX } from './utils';
24+
import { handleIntegrationTask } from './tasks';
25+
import type { GithubRuntimeContext, IntegrationTask } from './types';
26+
import { arrayToHex, BRANCH_REF_PREFIX, safeCompare } from './utils';
2627
import { handlePullRequestEvents, handlePushEvent, verifyGitHubWebhookSignature } from './webhooks';
2728

2829
const logger = Logger('github');
@@ -38,6 +39,61 @@ const handleFetchEvent: FetchEventCallback<GithubRuntimeContext> = async (reques
3839
).pathname,
3940
});
4041

42+
async function verifyIntegrationSignature(
43+
payload: string,
44+
signature: string,
45+
secret: string
46+
): Promise<boolean> {
47+
if (!signature) {
48+
return false;
49+
}
50+
51+
const algorithm = { name: 'HMAC', hash: 'SHA-256' };
52+
const enc = new TextEncoder();
53+
const key = await crypto.subtle.importKey('raw', enc.encode(secret), algorithm, false, [
54+
'sign',
55+
'verify',
56+
]);
57+
const signed = await crypto.subtle.sign(algorithm.name, key, enc.encode(payload));
58+
const expectedSignature = arrayToHex(signed);
59+
60+
return safeCompare(expectedSignature, signature);
61+
}
62+
63+
/**
64+
* Handle integration tasks
65+
*/
66+
router.post('/tasks', async (request) => {
67+
const signature = request.headers.get('x-gitbook-integration-signature') ?? '';
68+
const payloadString = await request.text();
69+
70+
const verified = await verifyIntegrationSignature(
71+
payloadString,
72+
signature,
73+
environment.signingSecret!
74+
);
75+
76+
if (!verified) {
77+
return new Response('Invalid integration signature', {
78+
status: 400,
79+
});
80+
}
81+
82+
const { task } = JSON.parse(payloadString) as { task: IntegrationTask };
83+
logger.debug('verified & received integration task', task);
84+
85+
context.waitUntil(
86+
(async () => {
87+
await handleIntegrationTask(context, task);
88+
})()
89+
);
90+
91+
return new Response(JSON.stringify({ acknowledged: true }), {
92+
status: 200,
93+
headers: { 'content-type': 'application/json' },
94+
});
95+
});
96+
4197
/**
4298
* Handle GitHub App webhook events
4399
*/

0 commit comments

Comments
 (0)