使用 nginx' lua 验证 GitHub webhooks 并删除 cron-lock-file

using nginx' lua to validate GitHub webhooks and delete cron-lock-file

我有:

我想要的:

我现在想要 运行 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_sizebody_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