import { hmacSha256Hex, timingSafeEqualStrings } from "../crypto";
/**
* Accepts the signing schemes of the common forges: GitHub / Bitbucket (`X-Hub-Signature-256: sha256=<hmac>`),
* Gitea / Forgejo / Gogs (hex HMAC), GitLab (`X-Gitlab-Token` equal to the secret), and a bearer token or
* `?secret=` for anything else.
*/
export async function verifyMirrorHook(secret: string, request: Request, body: string): Promise<boolean> {
const headers = request.headers;
const hex = await hmacSha256Hex(secret, body);
const prefixed = [headers.get("x-hub-signature-256"), headers.get("x-hub-signature")];
for (const header of prefixed) {
if (header && timingSafeEqualStrings(`sha256=${hex}`, header.trim())) return true;
}
const plain = [headers.get("x-gitea-signature"), headers.get("x-forgejo-signature"), headers.get("x-gogs-signature")];
for (const header of plain) {
if (header && timingSafeEqualStrings(hex, header.trim().toLowerCase())) return true;
}
const authorization = headers.get("authorization") ?? "";
const bearer = authorization.toLowerCase().startsWith("bearer ")
? authorization.slice("bearer ".length).trim()
: null;
const tokens = [headers.get("x-gitlab-token"), bearer, new URL(request.url).searchParams.get("secret")];
return tokens.some((token) => token !== null && token !== "" && timingSafeEqualStrings(secret, token));
}