diff --git a/src/env.ts b/src/env.ts index 099efc6..fe6c982 100644 --- a/src/env.ts +++ b/src/env.ts @@ -3,7 +3,9 @@ import { z } from "zod"; const schema = z.object({ PORT: z.coerce.number(), + GITEA_WEBHOOK_SECRET: z.string(), }); + const result = schema.safeParse(process.env); if (!result.success) { console.error("ERROR: Environment variable validation failed:"); diff --git a/src/index.ts b/src/index.ts index d3ef563..7703ed9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import express from "express"; +import crypto from "crypto"; import { z } from "zod"; import { env } from "./env"; @@ -8,12 +9,38 @@ const webhookSchema = z.object({ const app = express(); -app.use(express.json()); +app.use( + express.raw({ + inflate: true, + limit: "100kb", + type: "application/json", + }), +); app.post("/", async (req, res) => { - const result = webhookSchema.safeParse(req.body); + const signature = req.headers["x-gitea-signature"] as string | undefined; + if (!signature) { + console.error("x-gitea-signature missing"); + res.sendStatus(401); + return; + } + + const hmac = crypto.createHmac("sha256", env.GITEA_WEBHOOK_SECRET); + hmac.update(req.body); + const payloadSignature = hmac.digest("hex"); + + if (signature !== payloadSignature) { + console.error("signature !== payload_signature"); + res.sendStatus(401); + return; + } + + const json = JSON.parse(req.body.toString()); + const result = webhookSchema.safeParse(json); + if (!result.success) { - res.sendStatus(200); + console.error("Invalid webhook payload:", result.error.issues); + res.sendStatus(400); return; }