Support Gitea webhooks in deploy listener
Some checks failed
Deploy Staging / Build backend (Nitro) (push) Has been cancelled
Deploy Staging / Deploy zu Hetzner (push) Has been cancelled
ci/woodpecker/push/woodpecker Pipeline was canceled

This commit is contained in:
chahinebrini 2026-06-18 08:46:20 +02:00
parent 2475c082de
commit 97206b7865

View File

@ -1,8 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
/** /**
* Rebreak GitHub Webhook Listener * Rebreak GitHub + Gitea Webhook Listener
* *
* Empfängt GitHub push-Events, validiert HMAC-SHA256-Signatur, * Empfängt GitHub- und Gitea-push-Events, validiert HMAC-SHA256-Signatur,
* und triggert das deploy.sh Script im Hintergrund. * und triggert das deploy.sh Script im Hintergrund.
* *
* Port: 9000 (intern, wird von nginx reverse-proxied) * Port: 9000 (intern, wird von nginx reverse-proxied)
@ -40,7 +40,7 @@ if (!WEBHOOK_SECRET) {
process.exit(1); process.exit(1);
} }
function verifySignature(secret, signature, payload) { function verifyGitHubSignature(secret, signature, payload) {
const hmac = crypto.createHmac("sha256", secret); const hmac = crypto.createHmac("sha256", secret);
hmac.update(payload, "utf-8"); hmac.update(payload, "utf-8");
const digest = `sha256=${hmac.digest("hex")}`; const digest = `sha256=${hmac.digest("hex")}`;
@ -54,6 +54,20 @@ function verifySignature(secret, signature, payload) {
} }
} }
function verifyGiteaSignature(secret, signature, payload) {
const hmac = crypto.createHmac("sha256", secret);
hmac.update(payload, "utf-8");
const digest = hmac.digest("hex");
try {
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest),
);
} catch {
return false;
}
}
// Deploy-Queue: verhindert parallele Builds (OOM-Schutz auf 4 GB RAM) // Deploy-Queue: verhindert parallele Builds (OOM-Schutz auf 4 GB RAM)
let deployRunning = false; let deployRunning = false;
let pendingDeploy = false; let pendingDeploy = false;
@ -107,19 +121,33 @@ const server = http.createServer((req, res) => {
let body = ""; let body = "";
req.on("data", (chunk) => (body += chunk)); req.on("data", (chunk) => (body += chunk));
req.on("end", () => { req.on("end", () => {
const sig = req.headers["x-hub-signature-256"]; const githubSig = req.headers["x-hub-signature-256"];
if (!sig) { const giteaSig = req.headers["x-gitea-signature"];
const event = req.headers["x-github-event"] || req.headers["x-gitea-event"];
if (!githubSig && !giteaSig) {
res.writeHead(401); res.writeHead(401);
res.end(JSON.stringify({ error: "Missing signature" })); res.end(JSON.stringify({ error: "Missing signature" }));
return; return;
} }
if (!verifySignature(WEBHOOK_SECRET, sig, body)) { const valid = githubSig
? verifyGitHubSignature(WEBHOOK_SECRET, githubSig, body)
: verifyGiteaSignature(WEBHOOK_SECRET, giteaSig, body);
if (!valid) {
res.writeHead(401); res.writeHead(401);
res.end(JSON.stringify({ error: "Invalid signature" })); res.end(JSON.stringify({ error: "Invalid signature" }));
return; return;
} }
if (event && event !== "push") {
console.log(`[Webhook] Ignoring non-push event: ${event}`);
res.writeHead(200);
res.end(JSON.stringify({ ok: false, reason: "Not a push event", event }));
return;
}
let payload; let payload;
try { try {
payload = JSON.parse(body); payload = JSON.parse(body);