Skip to content

Instantly share code, notes, and snippets.

@hangj
Forked from samael500/handler.lua
Last active September 20, 2019 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hangj/ce6aabac77e96b010e3b361e18422013 to your computer and use it in GitHub Desktop.
Save hangj/ce6aabac77e96b010e3b361e18422013 to your computer and use it in GitHub Desktop.
Validating payloads from GitHub webhooks with Nginx + Lua
-- $ sudo opm get jkeys089/lua-resty-hmac
local shell = require "resty.shell"
local cjson = require "cjson.safe"
local hmac = require "resty.hmac"
local secret = '<MY SUPER SECRET>'
local event = 'push'
local branch = 'refs/heads/master'
ngx.header.content_type = "text/plain; charset=utf-8"
local stdin = ""
local timeout = 50 * 1000 -- ms
local max_size = 4096*4 -- byte
if ngx.req.get_method():upper() ~= "POST" then
ngx.log(ngx.ERR, "wrong event request method: ", ngx.req.get_method())
return ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
local headers = ngx.req.get_headers()
if not headers['X-GitHub-Event'] or headers['X-GitHub-Event']:upper() ~= event:upper() then
ngx.log(ngx.ERR, "wrong event type: ", headers['X-GitHub-Event'])
return ngx.exit(ngx.HTTP_NOT_ACCEPTABLE)
end
if headers['Content-Type'] ~= 'application/json' then
ngx.log(ngx.ERR, "wrong content type header: ", headers['Content-Type'])
return ngx.exit (ngx.HTTP_NOT_ACCEPTABLE)
end
ngx.req.read_body()
local data = ngx.req.get_body_data()
local args = ngx.req.get_uri_args()
if not data then
ngx.log(ngx.ERR, "failed to get request body")
return ngx.exit (ngx.HTTP_BAD_REQUEST)
end
local signature = headers['X-Hub-Signature']
local hmac_sha1 = hmac:new(secret, hmac.ALGOS.SHA1)
if not hmac_sha1 then
ngx.log(ngx.ERR, "falied to create hmac_sha1 object")
ngx.say("falied to create hmac_sha1 object")
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
-- local ok = hmac_sha1:update(data)
local hex = hmac_sha1:final(data, true)
if not hex then
ngx.log(ngx.ERR, "failed to add data")
ngx.say("failed to add data")
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
hmac_sha1:reset()
hex = "sha1=" .. hex
if hex ~= signature then
ngx.log(ngx.ERR, "wrong webhook signature ", hex, " ", signature)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
data = cjson.decode(data)
if data.ref ~= branch then
ngx.say("Skip branch ", data.ref)
return ngx.exit(ngx.HTTP_OK)
end
---- deploy ----
local cmd = "./reload.sh"
local ok, stdout, stderr, reason, status = shell.run(cmd, stdin, timeout, max_size)
local str = string.format("./reload.sh: \nok=%s\nstdout=%s\nstderr=%s\nreason=%s\nstatus=%s\n", ok, stdout, stderr, reason, status)
ngx.log(ngx.ERR, "deploy: ", str)
ngx.say(str)
if status ~= 0 then
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
local mail = require "resty.mail"
local mailer = mail.new({
host = "smtp.qq.com",
port = 587,
starttls = true,
username = "1000@qq.com",
password = "xxxx", -- 邮箱需要设置开启 smtp 服务,这里填写授权码
})
local ok, err = mailer:send({
from = "server <1000@qq.com>",
to = { "1111@qq.com" },
subject = "deployed " .. (status == 0 and "SUCCESS" or "FAILED"),
text = "text",
html = "<h1>Header.</h1>",
})
if not ok then
ngx.log(ngx.ERR, "mailer:send error: ", err)
end
server {
# ....
location /deploy {
client_body_buffer_size 3M;
client_max_body_size 3M;
content_by_lua_file /path/to/deploy.lua;
}
}
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
cd $BASEDIR
git pull
sudo openresty -p `pwd` -c conf/nginx.conf -t || exit 1
ps -ef | grep openresty | grep -v grep
if [ $? -eq 0 ]
then
sudo openresty -p `pwd` -c conf/nginx.conf -s reload
else
sudo openresty -p `pwd` -c conf/nginx.conf
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment