|
|
@@ -0,0 +1,64 @@
|
|
|
+#!/usr/bin/env node
|
|
|
+// webhook-server.js — nhận webhook từ Gogs và trigger deploy
|
|
|
+// Run: node webhook-server.js [port]
|
|
|
+//
|
|
|
+// Gogs webhook URL: http://<pi-ip>:9000/webhook
|
|
|
+
|
|
|
+const http = require('http')
|
|
|
+
|
|
|
+const PORT = process.env['WEBHOOK_PORT'] || 9000
|
|
|
+const DEPLOY_SCRIPT = process.env['DEPLOY_SCRIPT'] || '/opt/timelapse/scripts/deploy.sh'
|
|
|
+const WEBHOOK_SECRET = process.env['WEBHOOK_SECRET'] || ''
|
|
|
+
|
|
|
+function verifySignature(body, signature) {
|
|
|
+ if (!WEBHOOK_SECRET) return true
|
|
|
+ const crypto = require('crypto')
|
|
|
+ const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET)
|
|
|
+ hmac.update(body)
|
|
|
+ const expected = 'sha256=' + hmac.digest('hex')
|
|
|
+ return crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expected))
|
|
|
+}
|
|
|
+
|
|
|
+const server = http.createServer((req, res) => {
|
|
|
+ if (req.method !== 'POST' || req.url !== '/webhook') {
|
|
|
+ res.writeHead(404)
|
|
|
+ res.end('Not found')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let body = ''
|
|
|
+ req.on('data', chunk => { body += chunk.toString() })
|
|
|
+ req.on('end', () => {
|
|
|
+ const signature = req.headers['x-gogs-signature'] || req.headers['x-hub-signature-256'] || ''
|
|
|
+ if (!verifySignature(body, signature)) {
|
|
|
+ res.writeHead(401)
|
|
|
+ res.end('Unauthorized')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let payload
|
|
|
+ try { payload = JSON.parse(body) } catch { payload = {} }
|
|
|
+
|
|
|
+ const branch = payload.ref ? payload.ref.replace('refs/heads/', '') : 'main'
|
|
|
+ console.log(`[${new Date().toISOString()}] Webhook received — branch: ${branch}`)
|
|
|
+
|
|
|
+ res.writeHead(200, { 'Content-Type': 'application/json' })
|
|
|
+ res.end(JSON.stringify({ ok: true, branch }))
|
|
|
+
|
|
|
+ // Trigger deploy async
|
|
|
+ const { spawn } = require('child_process')
|
|
|
+ const deploy = spawn('bash', [DEPLOY_SCRIPT, branch], {
|
|
|
+ cwd: '/opt/timelapse',
|
|
|
+ env: { ...process.env, DEPLOY_BRANCH: branch },
|
|
|
+ })
|
|
|
+ deploy.stdout.on('data', d => process.stdout.write(d))
|
|
|
+ deploy.stderr.on('data', d => process.stderr.write(d))
|
|
|
+ deploy.on('exit', code => {
|
|
|
+ console.log(`[${new Date().toISOString()}] Deploy exited with code ${code}`)
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+server.listen(PORT, () => {
|
|
|
+ console.log(`Webhook server listening on http://0.0.0.0:${PORT}/webhook`)
|
|
|
+})
|