bunkerized-nginx/lua/api.lua
2022-06-03 17:24:14 +02:00

176 lines
5.2 KiB
Lua

local datastore = require "datastore"
local utils = require "utils"
local cjson = require "cjson"
local plugins = require "plugins"
local upload = require "resty.upload"
local logger = require "logger"
local api = {global = {GET = {}, POST = {}, PUT = {}, DELETE = {}}}
api.response = function(self, http_status, api_status, msg)
local resp = {}
resp["status"] = api_status
resp["msg"] = msg
return http_status, resp
end
api.global.GET["^/ping$"] = function(api)
return api:response(ngx.HTTP_OK, "success", "pong")
end
api.global.POST["^/jobs$"] = function(api)
-- ngx.req.read_body()
-- local data = ngx.req.get_body_data()
-- if not data then
-- local data_file = ngx.req.get_body_file()
-- if data_file then
-- local file = io.open(data_file)
-- data = file:read("*a")
-- file:close()
-- end
-- end
-- local ok, env = pcall(cjson.decode, data)
-- if not ok then
-- return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
-- end
-- local file = io.open("/opt/bunkerweb/tmp/jobs.env", "w+")
-- for k, v in pairs(env) do
-- file:write(k .. "=" .. v .. "\n")
-- end
-- file:close()
local status = os.execute("/opt/bunkerweb/helpers/scheduler-restart.sh")
if status == 0 then
return api:response(ngx.HTTP_OK, "success", "jobs executed and scheduler started")
end
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
end
api.global.POST["^/reload$"] = function(api)
local status = os.execute("/usr/sbin/nginx -s reload")
if status == 0 then
return api:response(ngx.HTTP_OK, "success", "reload successful")
end
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
end
api.global.POST["^/stop$"] = function(api)
local status = os.execute("/usr/sbin/nginx -s quit")
if status == 0 then
return api:response(ngx.HTTP_OK, "success", "stop successful")
end
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "exit status = " .. tostring(status))
end
api.global.POST["^/confs$"] = function(api)
local tmp = "/opt/bunkerweb/tmp/api_" .. ngx.var.uri:sub(2) .. ".tar.gz"
local destination = "/opt/bunkerweb/" .. ngx.var.uri:sub(2)
if ngx.var.uri == "/confs" then
destination = "/etc/nginx"
elseif ngx.var.uri == "/data" then
destination = "/data"
end
local form, err = upload:new(4096)
if not form then
return api:response(ngx.HTTP_BAD_REQUEST, "error", err)
end
form:set_timeout(1000)
local file = io.open(tmp, "w+")
while true do
local typ, res, err = form:read()
if not typ then
file:close()
return api:response(ngx.HTTP_BAD_REQUEST, "error", err)
end
if typ == "eof" then
break
end
if typ == "body" then
file:write(res)
end
end
file:flush()
file:close()
local status = os.execute("rm -rf " .. destination .. "/*")
if status ~= 0 then
return api:response(ngx.HTTP_BAD_REQUEST, "error", "can't remove old files")
end
status = os.execute("tar xzf " .. tmp .. " -C " .. destination)
if status ~= 0 then
return api:response(ngx.HTTP_BAD_REQUEST, "error", "can't extract archive")
end
return api:response(ngx.HTTP_OK, "success", "saved data at " .. destination)
end
api.global.POST["^/data$"] = api.global.POST["^/confs$"]
api.global.POST["^/unban$"] = function(api)
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then
local data_file = ngx.req.get_body_file()
if data_file then
local file = io.open(data_file)
data = file:read("*a")
file:close()
end
end
local ok, ip = pcall(cjson.decode, data)
if not ok then
return api:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. env)
end
datastore:delete("bans_ip_" .. ip["ip"])
return api:response(ngx.HTTP_OK, "success", "ip " .. ip["ip"] .. " unbanned")
end
api.is_allowed_ip = function(self)
local data, err = datastore:get("api_whitelist_ip")
if not data then
return false, "can't access api_allowed_ips in datastore"
end
if utils.is_ip_in_networks(ngx.var.remote_addr, cjson.decode(data).data) then
return true, "ok"
end
return false, "IP is not in API_WHITELIST_IP"
end
api.do_api_call = function(self)
if self.global[ngx.var.request_method] ~= nil then
for uri, api_fun in pairs(self.global[ngx.var.request_method]) do
if string.match(ngx.var.uri, uri) then
local status, resp = api_fun(self)
local ret = true
if status ~= ngx.HTTP_OK then
ret = false
end
return ret, resp["msg"], status, cjson.encode(resp)
end
end
end
local list, err = plugins:list()
if not list then
local status, resp = self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", "can't list loaded plugins : " .. err)
return false, resp["msg"], ngx.HTTP_INTERNAL_SERVER_ERROR, resp
end
for i, plugin in ipairs(list) do
if pcall(require, plugin.id .. "/" .. plugin.id) then
local plugin_lua = require(plugin.id .. "/" .. plugin.id)
if plugin_lua.api ~= nil then
local matched, status, resp = plugin_lua.api()
if matched then
local ret = true
if status ~= ngx.HTTP_OK then
ret = false
end
return ret, resp["msg"], status, cjson.encode(resp)
end
end
end
end
local resp = {}
resp["status"] = "error"
resp["msg"] = "not found"
return false, "error", ngx.HTTP_NOT_FOUND, cjson.encode(resp)
end
return api