2022-09-06 01:56:57 +00:00
|
|
|
import { http } from "../deps.ts";
|
2022-09-04 12:54:10 +00:00
|
|
|
import config from "./config.ts";
|
2022-09-04 12:39:03 +00:00
|
|
|
import { hasKey, verify } from "./crypto.ts";
|
2022-09-02 23:35:09 +00:00
|
|
|
import filterWebhook from "./filter.ts";
|
2022-09-03 14:59:34 +00:00
|
|
|
import { UrlConfig } from "./types.d.ts";
|
2022-09-06 01:56:57 +00:00
|
|
|
import { parseBool, requestLog } from "./util.ts";
|
2022-09-03 18:11:04 +00:00
|
|
|
import { sendWebhook } from "./webhook.ts";
|
2022-09-02 20:24:33 +00:00
|
|
|
|
2022-09-06 02:16:06 +00:00
|
|
|
export default async function handle(
|
|
|
|
req: Request,
|
|
|
|
): Promise<Response | [Response, Record<string, string>]> {
|
2022-09-04 12:54:10 +00:00
|
|
|
const url = new URL(req.url);
|
|
|
|
|
|
|
|
// redirect to repo if `GET /`
|
|
|
|
if (req.method === "GET" && config.mainRedirect && url.pathname === "/") {
|
|
|
|
return Response.redirect(config.mainRedirect);
|
|
|
|
}
|
|
|
|
|
|
|
|
// everything else should be a POST
|
2022-09-02 20:24:33 +00:00
|
|
|
if (req.method !== "POST") {
|
|
|
|
throw http.createHttpError(405);
|
|
|
|
}
|
|
|
|
|
|
|
|
// split url into parts
|
|
|
|
const [, id, token] = url.pathname.split("/");
|
2022-09-04 12:39:03 +00:00
|
|
|
if (!id || !token) {
|
2022-09-02 20:24:33 +00:00
|
|
|
throw http.createHttpError(400);
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify signature
|
2022-09-04 12:39:03 +00:00
|
|
|
if (hasKey) {
|
|
|
|
const signature = url.searchParams.get("sig");
|
|
|
|
if (!signature) throw http.createHttpError(400);
|
|
|
|
if (!(await verify(`${id}/${token}`, signature))) throw http.createHttpError(403);
|
2022-09-02 20:24:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// extract data
|
|
|
|
const urlConfig = getUrlConfig(url.searchParams);
|
|
|
|
const data = await req.text();
|
|
|
|
const json = JSON.parse(data);
|
|
|
|
|
|
|
|
// do the thing
|
2022-09-06 19:21:40 +00:00
|
|
|
const filterReason = await filterWebhook(req.headers, json, urlConfig);
|
2022-09-02 20:24:33 +00:00
|
|
|
if (filterReason !== null) {
|
2022-09-06 01:56:57 +00:00
|
|
|
const reqLog = requestLog(req.headers);
|
|
|
|
reqLog.debug(`handler: ignored due to '${filterReason}'`);
|
2022-09-02 20:24:33 +00:00
|
|
|
return new Response(`Ignored by webhook filter (reason: ${filterReason})`, { status: 203 });
|
|
|
|
}
|
|
|
|
|
|
|
|
return await sendWebhook(id, token, req.headers, data);
|
|
|
|
}
|
2022-09-02 23:36:32 +00:00
|
|
|
|
|
|
|
function getUrlConfig(params: URLSearchParams): UrlConfig {
|
|
|
|
const config: UrlConfig = {};
|
|
|
|
for (const [key, value] of params) {
|
|
|
|
switch (key) {
|
|
|
|
case "sig":
|
|
|
|
continue;
|
|
|
|
case "allowBranches":
|
|
|
|
config.allowBranches = value.split(",");
|
|
|
|
break;
|
|
|
|
case "hideTags":
|
2022-09-03 18:14:57 +00:00
|
|
|
config.hideTags = parseBool(value);
|
2022-09-02 23:36:32 +00:00
|
|
|
break;
|
2022-09-03 15:10:58 +00:00
|
|
|
case "commentBurstLimit":
|
|
|
|
config.commentBurstLimit = parseInt(value);
|
|
|
|
break;
|
2022-09-02 23:36:32 +00:00
|
|
|
default:
|
|
|
|
throw http.createHttpError(418, `Unknown config option: ${key}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
}
|