使用 nginx' lua 验证 GitHub webhooks 并删除 cron-lock-file
using nginx' lua to validate GitHub webhooks and delete cron-lock-file
我有:
- GNU/Linux主机
- nginx 已启动并且 运行ning
- 有一个 cron-job 计划在特定文件被删除后立即 运行(类似于 运行-crons)
- GitHub 当有人推送到存储库时发送一个 webhook
我想要的:
我现在想要 运行 lua 或任何类似于解析 GitHub 的请求并验证它然后删除文件(如果请求有效的话当然).
最好所有这一切都应该在没有维护额外 PHP 安装的麻烦的情况下进行,因为目前有 none,或者需要使用 fcgiwrap 或类似的。
模板:
在 nginx 方面我有等同于
的东西
location /deploy {
# execute lua (or equivalent) here
}
此解决方案未实现对 GitHub 挂钩的验证,并假定您安装了 lua 扩展和 cjson 模块:
location = /location {
default_type 'text/plain';
content_by_lua_block {
local cjson = require "cjson.safe"
ngx.req.read_body()
local data = ngx.req.get_body_data()
if
data
then
local obj = cjson.decode(data)
if
# checksum checking should go here
(obj and obj.repository and obj.repository.full_name) == "user/reponame"
then
local file = io.open("<your file>","w")
if
file
then
file:close()
ngx.say("success")
else
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
else
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
else
ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
}
}
要阅读 json GH webhook 主体,您需要使用 JSON4Lua lib, and to validate HMAC signature use luacrypto。
预配置
安装所需的模块
$ sudo luarocks install JSON4Lua
$ sudo luarocks install luacrypto
在 Nginx 中定义部署位置
location /deploy {
client_body_buffer_size 3M;
client_max_body_size 3M;
content_by_lua_file /path/to/handler.lua;
}
max_body_size
和body_buffer_size
应该相等以防止出错
request body in temp file not supported
https://github.com/openresty/lua-nginx-module/issues/521
处理网络钩子
获取请求负载数据并检查是否正确
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then
ngx.log(ngx.ERR, "failed to get request body")
return ngx.exit (ngx.HTTP_BAD_REQUEST)
end
使用 luacrypto 验证 GH 签名
local function verify_signature (hub_sign, data)
local sign = 'sha1=' .. crypto.hmac.digest('sha1', data, secret)
-- this is simple comparison, but it's better to use a constant time comparison
return hub_sign == sign
end
-- validate GH signature
if not verify_signature(headers['X-Hub-Signature'], data) then
ngx.log(ngx.ERR, "wrong webhook signature")
return ngx.exit (ngx.HTTP_FORBIDDEN)
end
将数据解析为 json 并检查主分支,用于部署
data = json.decode(data)
-- on master branch
if data['ref'] ~= branch then
ngx.say("Skip branch ", data['ref'])
return ngx.exit (ngx.HTTP_OK)
end
如果都正确,调用部署函数
local function deploy ()
-- run command for deploy
local handle = io.popen("cd /path/to/repo && sudo -u username git pull")
local result = handle:read("*a")
handle:close()
ngx.say (result)
return ngx.exit (ngx.HTTP_OK)
end
示例
常量时间字符串比较示例
local function const_eq (a, b)
-- Check is string equals, constant time exec
getmetatable('').__index = function (str, i)
return string.sub(str, i, i)
end
local diff = string.len(a) == string.len(b)
for i = 1, math.min(string.len(a), string.len(b)) do
diff = (a[i] == b[i]) and diff
end
return diff
end
我如何在 github 要点中使用它的完整示例 https://gist.github.com/Samael500/5dbdf6d55838f841a08eb7847ad1c926
我有:
- GNU/Linux主机
- nginx 已启动并且 运行ning
- 有一个 cron-job 计划在特定文件被删除后立即 运行(类似于 运行-crons)
- GitHub 当有人推送到存储库时发送一个 webhook
我想要的:
我现在想要 运行 lua 或任何类似于解析 GitHub 的请求并验证它然后删除文件(如果请求有效的话当然).
最好所有这一切都应该在没有维护额外 PHP 安装的麻烦的情况下进行,因为目前有 none,或者需要使用 fcgiwrap 或类似的。
模板:
在 nginx 方面我有等同于
的东西location /deploy {
# execute lua (or equivalent) here
}
此解决方案未实现对 GitHub 挂钩的验证,并假定您安装了 lua 扩展和 cjson 模块:
location = /location {
default_type 'text/plain';
content_by_lua_block {
local cjson = require "cjson.safe"
ngx.req.read_body()
local data = ngx.req.get_body_data()
if
data
then
local obj = cjson.decode(data)
if
# checksum checking should go here
(obj and obj.repository and obj.repository.full_name) == "user/reponame"
then
local file = io.open("<your file>","w")
if
file
then
file:close()
ngx.say("success")
else
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
else
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
else
ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
}
}
要阅读 json GH webhook 主体,您需要使用 JSON4Lua lib, and to validate HMAC signature use luacrypto。
预配置
安装所需的模块
$ sudo luarocks install JSON4Lua
$ sudo luarocks install luacrypto
在 Nginx 中定义部署位置
location /deploy {
client_body_buffer_size 3M;
client_max_body_size 3M;
content_by_lua_file /path/to/handler.lua;
}
max_body_size
和body_buffer_size
应该相等以防止出错
request body in temp file not supported
https://github.com/openresty/lua-nginx-module/issues/521
处理网络钩子
获取请求负载数据并检查是否正确
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then
ngx.log(ngx.ERR, "failed to get request body")
return ngx.exit (ngx.HTTP_BAD_REQUEST)
end
使用 luacrypto 验证 GH 签名
local function verify_signature (hub_sign, data)
local sign = 'sha1=' .. crypto.hmac.digest('sha1', data, secret)
-- this is simple comparison, but it's better to use a constant time comparison
return hub_sign == sign
end
-- validate GH signature
if not verify_signature(headers['X-Hub-Signature'], data) then
ngx.log(ngx.ERR, "wrong webhook signature")
return ngx.exit (ngx.HTTP_FORBIDDEN)
end
将数据解析为 json 并检查主分支,用于部署
data = json.decode(data)
-- on master branch
if data['ref'] ~= branch then
ngx.say("Skip branch ", data['ref'])
return ngx.exit (ngx.HTTP_OK)
end
如果都正确,调用部署函数
local function deploy ()
-- run command for deploy
local handle = io.popen("cd /path/to/repo && sudo -u username git pull")
local result = handle:read("*a")
handle:close()
ngx.say (result)
return ngx.exit (ngx.HTTP_OK)
end
示例
常量时间字符串比较示例
local function const_eq (a, b)
-- Check is string equals, constant time exec
getmetatable('').__index = function (str, i)
return string.sub(str, i, i)
end
local diff = string.len(a) == string.len(b)
for i = 1, math.min(string.len(a), string.len(b)) do
diff = (a[i] == b[i]) and diff
end
return diff
end
我如何在 github 要点中使用它的完整示例 https://gist.github.com/Samael500/5dbdf6d55838f841a08eb7847ad1c926