UNPKG

18.9 kBJavaScriptView Raw
1// pkg/dist-src/createLogger.js
2var createLogger = (logger) => ({
3 debug: () => {
4 },
5 info: () => {
6 },
7 warn: console.warn.bind(console),
8 error: console.error.bind(console),
9 ...logger
10});
11
12// pkg/dist-src/generated/webhook-names.js
13var emitterEventNames = [
14 "branch_protection_configuration",
15 "branch_protection_configuration.disabled",
16 "branch_protection_configuration.enabled",
17 "branch_protection_rule",
18 "branch_protection_rule.created",
19 "branch_protection_rule.deleted",
20 "branch_protection_rule.edited",
21 "check_run",
22 "check_run.completed",
23 "check_run.created",
24 "check_run.requested_action",
25 "check_run.rerequested",
26 "check_suite",
27 "check_suite.completed",
28 "check_suite.requested",
29 "check_suite.rerequested",
30 "code_scanning_alert",
31 "code_scanning_alert.appeared_in_branch",
32 "code_scanning_alert.closed_by_user",
33 "code_scanning_alert.created",
34 "code_scanning_alert.fixed",
35 "code_scanning_alert.reopened",
36 "code_scanning_alert.reopened_by_user",
37 "commit_comment",
38 "commit_comment.created",
39 "create",
40 "custom_property",
41 "custom_property.created",
42 "custom_property.deleted",
43 "custom_property.updated",
44 "custom_property_values",
45 "custom_property_values.updated",
46 "delete",
47 "dependabot_alert",
48 "dependabot_alert.auto_dismissed",
49 "dependabot_alert.auto_reopened",
50 "dependabot_alert.created",
51 "dependabot_alert.dismissed",
52 "dependabot_alert.fixed",
53 "dependabot_alert.reintroduced",
54 "dependabot_alert.reopened",
55 "deploy_key",
56 "deploy_key.created",
57 "deploy_key.deleted",
58 "deployment",
59 "deployment.created",
60 "deployment_protection_rule",
61 "deployment_protection_rule.requested",
62 "deployment_review",
63 "deployment_review.approved",
64 "deployment_review.rejected",
65 "deployment_review.requested",
66 "deployment_status",
67 "deployment_status.created",
68 "discussion",
69 "discussion.answered",
70 "discussion.category_changed",
71 "discussion.closed",
72 "discussion.created",
73 "discussion.deleted",
74 "discussion.edited",
75 "discussion.labeled",
76 "discussion.locked",
77 "discussion.pinned",
78 "discussion.reopened",
79 "discussion.transferred",
80 "discussion.unanswered",
81 "discussion.unlabeled",
82 "discussion.unlocked",
83 "discussion.unpinned",
84 "discussion_comment",
85 "discussion_comment.created",
86 "discussion_comment.deleted",
87 "discussion_comment.edited",
88 "fork",
89 "github_app_authorization",
90 "github_app_authorization.revoked",
91 "gollum",
92 "installation",
93 "installation.created",
94 "installation.deleted",
95 "installation.new_permissions_accepted",
96 "installation.suspend",
97 "installation.unsuspend",
98 "installation_repositories",
99 "installation_repositories.added",
100 "installation_repositories.removed",
101 "installation_target",
102 "installation_target.renamed",
103 "issue_comment",
104 "issue_comment.created",
105 "issue_comment.deleted",
106 "issue_comment.edited",
107 "issues",
108 "issues.assigned",
109 "issues.closed",
110 "issues.deleted",
111 "issues.demilestoned",
112 "issues.edited",
113 "issues.labeled",
114 "issues.locked",
115 "issues.milestoned",
116 "issues.opened",
117 "issues.pinned",
118 "issues.reopened",
119 "issues.transferred",
120 "issues.unassigned",
121 "issues.unlabeled",
122 "issues.unlocked",
123 "issues.unpinned",
124 "label",
125 "label.created",
126 "label.deleted",
127 "label.edited",
128 "marketplace_purchase",
129 "marketplace_purchase.cancelled",
130 "marketplace_purchase.changed",
131 "marketplace_purchase.pending_change",
132 "marketplace_purchase.pending_change_cancelled",
133 "marketplace_purchase.purchased",
134 "member",
135 "member.added",
136 "member.edited",
137 "member.removed",
138 "membership",
139 "membership.added",
140 "membership.removed",
141 "merge_group",
142 "merge_group.checks_requested",
143 "merge_group.destroyed",
144 "meta",
145 "meta.deleted",
146 "milestone",
147 "milestone.closed",
148 "milestone.created",
149 "milestone.deleted",
150 "milestone.edited",
151 "milestone.opened",
152 "org_block",
153 "org_block.blocked",
154 "org_block.unblocked",
155 "organization",
156 "organization.deleted",
157 "organization.member_added",
158 "organization.member_invited",
159 "organization.member_removed",
160 "organization.renamed",
161 "package",
162 "package.published",
163 "package.updated",
164 "page_build",
165 "personal_access_token_request",
166 "personal_access_token_request.approved",
167 "personal_access_token_request.cancelled",
168 "personal_access_token_request.created",
169 "personal_access_token_request.denied",
170 "ping",
171 "project",
172 "project.closed",
173 "project.created",
174 "project.deleted",
175 "project.edited",
176 "project.reopened",
177 "project_card",
178 "project_card.converted",
179 "project_card.created",
180 "project_card.deleted",
181 "project_card.edited",
182 "project_card.moved",
183 "project_column",
184 "project_column.created",
185 "project_column.deleted",
186 "project_column.edited",
187 "project_column.moved",
188 "projects_v2",
189 "projects_v2.closed",
190 "projects_v2.created",
191 "projects_v2.deleted",
192 "projects_v2.edited",
193 "projects_v2.reopened",
194 "projects_v2_item",
195 "projects_v2_item.archived",
196 "projects_v2_item.converted",
197 "projects_v2_item.created",
198 "projects_v2_item.deleted",
199 "projects_v2_item.edited",
200 "projects_v2_item.reordered",
201 "projects_v2_item.restored",
202 "public",
203 "pull_request",
204 "pull_request.assigned",
205 "pull_request.auto_merge_disabled",
206 "pull_request.auto_merge_enabled",
207 "pull_request.closed",
208 "pull_request.converted_to_draft",
209 "pull_request.demilestoned",
210 "pull_request.dequeued",
211 "pull_request.edited",
212 "pull_request.enqueued",
213 "pull_request.labeled",
214 "pull_request.locked",
215 "pull_request.milestoned",
216 "pull_request.opened",
217 "pull_request.ready_for_review",
218 "pull_request.reopened",
219 "pull_request.review_request_removed",
220 "pull_request.review_requested",
221 "pull_request.synchronize",
222 "pull_request.unassigned",
223 "pull_request.unlabeled",
224 "pull_request.unlocked",
225 "pull_request_review",
226 "pull_request_review.dismissed",
227 "pull_request_review.edited",
228 "pull_request_review.submitted",
229 "pull_request_review_comment",
230 "pull_request_review_comment.created",
231 "pull_request_review_comment.deleted",
232 "pull_request_review_comment.edited",
233 "pull_request_review_thread",
234 "pull_request_review_thread.resolved",
235 "pull_request_review_thread.unresolved",
236 "push",
237 "registry_package",
238 "registry_package.published",
239 "registry_package.updated",
240 "release",
241 "release.created",
242 "release.deleted",
243 "release.edited",
244 "release.prereleased",
245 "release.published",
246 "release.released",
247 "release.unpublished",
248 "repository",
249 "repository.archived",
250 "repository.created",
251 "repository.deleted",
252 "repository.edited",
253 "repository.privatized",
254 "repository.publicized",
255 "repository.renamed",
256 "repository.transferred",
257 "repository.unarchived",
258 "repository_advisory",
259 "repository_advisory.published",
260 "repository_advisory.reported",
261 "repository_dispatch",
262 "repository_dispatch.sample.collected",
263 "repository_import",
264 "repository_ruleset",
265 "repository_ruleset.created",
266 "repository_ruleset.deleted",
267 "repository_ruleset.edited",
268 "repository_vulnerability_alert",
269 "repository_vulnerability_alert.create",
270 "repository_vulnerability_alert.dismiss",
271 "repository_vulnerability_alert.reopen",
272 "repository_vulnerability_alert.resolve",
273 "secret_scanning_alert",
274 "secret_scanning_alert.created",
275 "secret_scanning_alert.reopened",
276 "secret_scanning_alert.resolved",
277 "secret_scanning_alert.revoked",
278 "secret_scanning_alert.validated",
279 "secret_scanning_alert_location",
280 "secret_scanning_alert_location.created",
281 "security_advisory",
282 "security_advisory.published",
283 "security_advisory.updated",
284 "security_advisory.withdrawn",
285 "security_and_analysis",
286 "sponsorship",
287 "sponsorship.cancelled",
288 "sponsorship.created",
289 "sponsorship.edited",
290 "sponsorship.pending_cancellation",
291 "sponsorship.pending_tier_change",
292 "sponsorship.tier_changed",
293 "star",
294 "star.created",
295 "star.deleted",
296 "status",
297 "team",
298 "team.added_to_repository",
299 "team.created",
300 "team.deleted",
301 "team.edited",
302 "team.removed_from_repository",
303 "team_add",
304 "watch",
305 "watch.started",
306 "workflow_dispatch",
307 "workflow_job",
308 "workflow_job.completed",
309 "workflow_job.in_progress",
310 "workflow_job.queued",
311 "workflow_job.waiting",
312 "workflow_run",
313 "workflow_run.completed",
314 "workflow_run.in_progress",
315 "workflow_run.requested"
316];
317
318// pkg/dist-src/event-handler/on.js
319function handleEventHandlers(state, webhookName, handler) {
320 if (!state.hooks[webhookName]) {
321 state.hooks[webhookName] = [];
322 }
323 state.hooks[webhookName].push(handler);
324}
325function receiverOn(state, webhookNameOrNames, handler) {
326 if (Array.isArray(webhookNameOrNames)) {
327 webhookNameOrNames.forEach(
328 (webhookName) => receiverOn(state, webhookName, handler)
329 );
330 return;
331 }
332 if (["*", "error"].includes(webhookNameOrNames)) {
333 const webhookName = webhookNameOrNames === "*" ? "any" : webhookNameOrNames;
334 const message = `Using the "${webhookNameOrNames}" event with the regular Webhooks.on() function is not supported. Please use the Webhooks.on${webhookName.charAt(0).toUpperCase() + webhookName.slice(1)}() method instead`;
335 throw new Error(message);
336 }
337 if (!emitterEventNames.includes(webhookNameOrNames)) {
338 state.log.warn(
339 `"${webhookNameOrNames}" is not a known webhook name (https://developer.github.com/v3/activity/events/types/)`
340 );
341 }
342 handleEventHandlers(state, webhookNameOrNames, handler);
343}
344function receiverOnAny(state, handler) {
345 handleEventHandlers(state, "*", handler);
346}
347function receiverOnError(state, handler) {
348 handleEventHandlers(state, "error", handler);
349}
350
351// pkg/dist-src/event-handler/wrap-error-handler.js
352function wrapErrorHandler(handler, error) {
353 let returnValue;
354 try {
355 returnValue = handler(error);
356 } catch (error2) {
357 console.log('FATAL: Error occurred in "error" event handler');
358 console.log(error2);
359 }
360 if (returnValue && returnValue.catch) {
361 returnValue.catch((error2) => {
362 console.log('FATAL: Error occurred in "error" event handler');
363 console.log(error2);
364 });
365 }
366}
367
368// pkg/dist-src/event-handler/receive.js
369function getHooks(state, eventPayloadAction, eventName) {
370 const hooks = [state.hooks[eventName], state.hooks["*"]];
371 if (eventPayloadAction) {
372 hooks.unshift(state.hooks[`${eventName}.${eventPayloadAction}`]);
373 }
374 return [].concat(...hooks.filter(Boolean));
375}
376function receiverHandle(state, event) {
377 const errorHandlers = state.hooks.error || [];
378 if (event instanceof Error) {
379 const error = Object.assign(new AggregateError([event], event.message), {
380 event
381 });
382 errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
383 return Promise.reject(error);
384 }
385 if (!event || !event.name) {
386 const error = new Error("Event name not passed");
387 throw new AggregateError([error], error.message);
388 }
389 if (!event.payload) {
390 const error = new Error("Event name not passed");
391 throw new AggregateError([error], error.message);
392 }
393 const hooks = getHooks(
394 state,
395 "action" in event.payload ? event.payload.action : null,
396 event.name
397 );
398 if (hooks.length === 0) {
399 return Promise.resolve();
400 }
401 const errors = [];
402 const promises = hooks.map((handler) => {
403 let promise = Promise.resolve(event);
404 if (state.transform) {
405 promise = promise.then(state.transform);
406 }
407 return promise.then((event2) => {
408 return handler(event2);
409 }).catch((error) => errors.push(Object.assign(error, { event })));
410 });
411 return Promise.all(promises).then(() => {
412 if (errors.length === 0) {
413 return;
414 }
415 const error = new AggregateError(
416 errors,
417 errors.map((error2) => error2.message).join("\n")
418 );
419 Object.assign(error, {
420 event
421 });
422 errorHandlers.forEach((handler) => wrapErrorHandler(handler, error));
423 throw error;
424 });
425}
426
427// pkg/dist-src/event-handler/remove-listener.js
428function removeListener(state, webhookNameOrNames, handler) {
429 if (Array.isArray(webhookNameOrNames)) {
430 webhookNameOrNames.forEach(
431 (webhookName) => removeListener(state, webhookName, handler)
432 );
433 return;
434 }
435 if (!state.hooks[webhookNameOrNames]) {
436 return;
437 }
438 for (let i = state.hooks[webhookNameOrNames].length - 1; i >= 0; i--) {
439 if (state.hooks[webhookNameOrNames][i] === handler) {
440 state.hooks[webhookNameOrNames].splice(i, 1);
441 return;
442 }
443 }
444}
445
446// pkg/dist-src/event-handler/index.js
447function createEventHandler(options) {
448 const state = {
449 hooks: {},
450 log: createLogger(options && options.log)
451 };
452 if (options && options.transform) {
453 state.transform = options.transform;
454 }
455 return {
456 on: receiverOn.bind(null, state),
457 onAny: receiverOnAny.bind(null, state),
458 onError: receiverOnError.bind(null, state),
459 removeListener: removeListener.bind(null, state),
460 receive: receiverHandle.bind(null, state)
461 };
462}
463
464// pkg/dist-src/index.js
465import { sign, verify as verify2 } from "@octokit/webhooks-methods";
466
467// pkg/dist-src/verify-and-receive.js
468import { verify } from "@octokit/webhooks-methods";
469async function verifyAndReceive(state, event) {
470 const matchesSignature = await verify(
471 state.secret,
472 event.payload,
473 event.signature
474 ).catch(() => false);
475 if (!matchesSignature) {
476 const error = new Error(
477 "[@octokit/webhooks] signature does not match event payload and secret"
478 );
479 return state.eventHandler.receive(
480 Object.assign(error, { event, status: 400 })
481 );
482 }
483 let payload;
484 try {
485 payload = JSON.parse(event.payload);
486 } catch (error) {
487 error.message = "Invalid JSON";
488 error.status = 400;
489 throw new AggregateError([error], error.message);
490 }
491 return state.eventHandler.receive({
492 id: event.id,
493 name: event.name,
494 payload
495 });
496}
497
498// pkg/dist-src/middleware/node/get-missing-headers.js
499var WEBHOOK_HEADERS = [
500 "x-github-event",
501 "x-hub-signature-256",
502 "x-github-delivery"
503];
504function getMissingHeaders(request) {
505 return WEBHOOK_HEADERS.filter((header) => !(header in request.headers));
506}
507
508// pkg/dist-src/middleware/node/get-payload.js
509function getPayload(request) {
510 if (typeof request.body === "object" && "rawBody" in request && request.rawBody instanceof Buffer) {
511 return Promise.resolve(request.rawBody.toString("utf8"));
512 } else if (typeof request.body === "string") {
513 return Promise.resolve(request.body);
514 }
515 return new Promise((resolve, reject) => {
516 let data = [];
517 request.on(
518 "error",
519 (error) => reject(new AggregateError([error], error.message))
520 );
521 request.on("data", (chunk) => data.push(chunk));
522 request.on(
523 "end",
524 () => (
525 // setImmediate improves the throughput by reducing the pressure from
526 // the event loop
527 setImmediate(
528 resolve,
529 data.length === 1 ? data[0].toString("utf8") : Buffer.concat(data).toString("utf8")
530 )
531 )
532 );
533 });
534}
535
536// pkg/dist-src/middleware/node/on-unhandled-request-default.js
537function onUnhandledRequestDefault(request, response) {
538 response.writeHead(404, {
539 "content-type": "application/json"
540 });
541 response.end(
542 JSON.stringify({
543 error: `Unknown route: ${request.method} ${request.url}`
544 })
545 );
546}
547
548// pkg/dist-src/middleware/node/middleware.js
549async function middleware(webhooks, options, request, response, next) {
550 let pathname;
551 try {
552 pathname = new URL(request.url, "http://localhost").pathname;
553 } catch (error) {
554 response.writeHead(422, {
555 "content-type": "application/json"
556 });
557 response.end(
558 JSON.stringify({
559 error: `Request URL could not be parsed: ${request.url}`
560 })
561 );
562 return true;
563 }
564 if (pathname !== options.path) {
565 next?.();
566 return false;
567 } else if (request.method !== "POST") {
568 onUnhandledRequestDefault(request, response);
569 return true;
570 }
571 if (!request.headers["content-type"] || !request.headers["content-type"].startsWith("application/json")) {
572 response.writeHead(415, {
573 "content-type": "application/json",
574 accept: "application/json"
575 });
576 response.end(
577 JSON.stringify({
578 error: `Unsupported "Content-Type" header value. Must be "application/json"`
579 })
580 );
581 return true;
582 }
583 const missingHeaders = getMissingHeaders(request).join(", ");
584 if (missingHeaders) {
585 response.writeHead(400, {
586 "content-type": "application/json"
587 });
588 response.end(
589 JSON.stringify({
590 error: `Required headers missing: ${missingHeaders}`
591 })
592 );
593 return true;
594 }
595 const eventName = request.headers["x-github-event"];
596 const signatureSHA256 = request.headers["x-hub-signature-256"];
597 const id = request.headers["x-github-delivery"];
598 options.log.debug(`${eventName} event received (id: ${id})`);
599 let didTimeout = false;
600 const timeout = setTimeout(() => {
601 didTimeout = true;
602 response.statusCode = 202;
603 response.end("still processing\n");
604 }, 9e3).unref();
605 try {
606 const payload = await getPayload(request);
607 await webhooks.verifyAndReceive({
608 id,
609 name: eventName,
610 payload,
611 signature: signatureSHA256
612 });
613 clearTimeout(timeout);
614 if (didTimeout) return true;
615 response.end("ok\n");
616 return true;
617 } catch (error) {
618 clearTimeout(timeout);
619 if (didTimeout) return true;
620 const err = Array.from(error.errors)[0];
621 const errorMessage = err.message ? `${err.name}: ${err.message}` : "Error: An Unspecified error occurred";
622 response.statusCode = typeof err.status !== "undefined" ? err.status : 500;
623 options.log.error(error);
624 response.end(
625 JSON.stringify({
626 error: errorMessage
627 })
628 );
629 return true;
630 }
631}
632
633// pkg/dist-src/middleware/node/index.js
634function createNodeMiddleware(webhooks, {
635 path = "/api/github/webhooks",
636 log = createLogger()
637} = {}) {
638 return middleware.bind(null, webhooks, {
639 path,
640 log
641 });
642}
643
644// pkg/dist-src/index.js
645var Webhooks = class {
646 sign;
647 verify;
648 on;
649 onAny;
650 onError;
651 removeListener;
652 receive;
653 verifyAndReceive;
654 constructor(options) {
655 if (!options || !options.secret) {
656 throw new Error("[@octokit/webhooks] options.secret required");
657 }
658 const state = {
659 eventHandler: createEventHandler(options),
660 secret: options.secret,
661 hooks: {},
662 log: createLogger(options.log)
663 };
664 this.sign = sign.bind(null, options.secret);
665 this.verify = verify2.bind(null, options.secret);
666 this.on = state.eventHandler.on;
667 this.onAny = state.eventHandler.onAny;
668 this.onError = state.eventHandler.onError;
669 this.removeListener = state.eventHandler.removeListener;
670 this.receive = state.eventHandler.receive;
671 this.verifyAndReceive = verifyAndReceive.bind(null, state);
672 }
673};
674export {
675 Webhooks,
676 createEventHandler,
677 createNodeMiddleware,
678 emitterEventNames
679};