webhook-server.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #!/usr/bin/env node
  2. // webhook-server.js — nhận webhook từ Gogs và trigger deploy
  3. // Run: node webhook-server.js [port]
  4. //
  5. // Gogs webhook URL: http://<pi-ip>:9000/webhook
  6. const http = require('http')
  7. const PORT = process.env['WEBHOOK_PORT'] || 9000
  8. const DEPLOY_SCRIPT = process.env['DEPLOY_SCRIPT'] || '/opt/timelapse/scripts/deploy.sh'
  9. const WEBHOOK_SECRET = process.env['WEBHOOK_SECRET'] || ''
  10. function verifySignature(body, signature) {
  11. if (!WEBHOOK_SECRET) return true
  12. const crypto = require('crypto')
  13. const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET)
  14. hmac.update(body)
  15. const expected = 'sha256=' + hmac.digest('hex')
  16. return crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expected))
  17. }
  18. const server = http.createServer((req, res) => {
  19. if (req.method !== 'POST' || req.url !== '/webhook') {
  20. res.writeHead(404)
  21. res.end('Not found')
  22. return
  23. }
  24. let body = ''
  25. req.on('data', chunk => { body += chunk.toString() })
  26. req.on('end', () => {
  27. const signature = req.headers['x-gogs-signature'] || req.headers['x-hub-signature-256'] || ''
  28. if (!verifySignature(body, signature)) {
  29. res.writeHead(401)
  30. res.end('Unauthorized')
  31. return
  32. }
  33. let payload
  34. try { payload = JSON.parse(body) } catch { payload = {} }
  35. const branch = payload.ref ? payload.ref.replace('refs/heads/', '') : 'main'
  36. console.log(`[${new Date().toISOString()}] Webhook received — branch: ${branch}`)
  37. res.writeHead(200, { 'Content-Type': 'application/json' })
  38. res.end(JSON.stringify({ ok: true, branch }))
  39. // Trigger deploy async
  40. const { spawn } = require('child_process')
  41. const deploy = spawn('bash', [DEPLOY_SCRIPT, branch], {
  42. cwd: '/opt/timelapse',
  43. env: { ...process.env, DEPLOY_BRANCH: branch },
  44. })
  45. deploy.stdout.on('data', d => process.stdout.write(d))
  46. deploy.stderr.on('data', d => process.stderr.write(d))
  47. deploy.on('exit', code => {
  48. console.log(`[${new Date().toISOString()}] Deploy exited with code ${code}`)
  49. })
  50. })
  51. })
  52. server.listen(PORT, () => {
  53. console.log(`Webhook server listening on http://0.0.0.0:${PORT}/webhook`)
  54. })