init work on refactoring

This commit is contained in:
florian 2023-04-11 13:52:09 +02:00
parent 92e6984581
commit afc0ac1988
No known key found for this signature in database
GPG Key ID: 3D80806F12602A7C
11 changed files with 442 additions and 193 deletions

View File

@ -1,3 +1,53 @@
local mlcache = require "resty.mlcache"
local clogger = require "bunkerweb.logger"
local class = require "middleclass"
local datastore = class("datastore")
-- Instantiate mlcache objects at module level (which will be cached when running init phase)
-- TODO : shm_miss, shm_locks
local shm = "datastore"
local ipc_shm = "datastore_ipc"
if not ngx.shared.datastore then
shm = "datastore_stream"
ipc_shm = "datastore_ipc_stream"
end
local store, err = mlcache.new(
"datastore",
shm,
{
lru_size = 100,
ttl = 0,
neg_ttl = 0,
shm_set_tries = 1,
ipc_shm = ipc_shm
}
)
local logger = clogger:new("DATASTORE")
if not store then
logger:log(ngx.ERR, "can't instantiate mlcache : " .. err)
end
function datastore:new()
self.store = store
self.logger = logger
end
function datastore:get(key)
local value, err, hit_level = self.store:get(key)
if err then
return false, err
end
self.logger:log(ngx.INFO, "hit level for " .. key .. " = " .. tostring(hit_level))
return true, value
end
function datastore:set(key, value)
local ok, err = self.store:set(key, nil, value)
if not ok then
return false, err
end
return true
end
local datastore = { dict = ngx.shared.datastore }

79
src/bw/lua/helpers.lua Normal file
View File

@ -0,0 +1,79 @@
local cjson = require "cjson"
local helpers = {}
helpers.load_plugin = function(json)
-- Open file
local file, err, nb = io.open(json, "r")
if not file then
return false, "can't load JSON at " .. json .. " : " .. err .. "(nb = " .. tostring(nb) .. ")"
end
-- Decode JSON
local ok, plugin = pcall(cjson.decode, file:read("*a"))
file:close()
if not ok then
return false, "invalid JSON at " .. json .. " : " .. err
end
-- Check fields
local missing_fields = {}
local required_fields = {"id", "order", "name", "description", "version", "settings"}
for i, field in ipairs(required_fields) do
if plugin[field] == nil then
valid_json = false
table.insert(missing_fields, field)
end
end
if #missing_fields > 0 then
return false, "missing field(s) " .. cjson.encode(missing_fields) .. " for JSON at " .. json
end
-- Return plugin
return plugin
end
helpers.new_plugin = function(id)
-- Require call
local ok, plugin_lua = pcall(require, id .. "/" .. id)
if not ok then
if plugin_lua:match("not found") then
return nil, "plugin " .. id .. " doesn't have LUA code"
end
return false, "require error for plugin " .. id .. " : " .. plugin_lua
end
-- New call
if plugin_lua.new == nil then
return false, "missing new() method for plugin " .. id
end
local ok, err = pcall(plugin_lua.new, plugin_lua)
if not ok then
return false, "new() call failed for plugin " .. id .. " : " .. err
end
-- Return plugin
return plugin_lua, "new() call successful for plugin " .. id
end
helpers.call_plugin = function(plugin, method)
-- Check if method is present
if plugin[method] == nil then
return nil, "missing " .. method .. "() method for plugin " .. plugin:get_id()
end
-- Call method
local ok, ret = pcall(plugin[method], plugin)
if not ok then
return false, plugin.id .. ":" .. method .. "() failed : " .. ret
end
-- Check values
local missing_values = {}
local required_values = {"ret", "msg"}
for i, value in ipairs(required_values) do
if ret[value] == nil then
table.insert(missing_values, value)
end
end
if #missing_values > 0 then
return false, "missing required return value(s) : " .. cjson.encode(missing_values)
end
-- Return
return true, ret
end
return helpers

View File

@ -4,6 +4,7 @@ local cjson = require "cjson"
local resolver = require "resty.dns.resolver"
local mmdb = require "mmdb"
local logger = require "logger"
local session = require "resty.session"
local utils = {}
@ -365,4 +366,54 @@ utils.get_deny_status = function()
return tonumber(status)
end
utils.get_session = function()
if ngx.ctx.session then
return ngx.ctx.session, ngx.ctx.session_err, ngx.ctx.session_exists
end
local _session, err, exists = session.start()
if err then
logger.log(ngx.ERR, "UTILS", "can't start session : " .. err)
end
ngx.ctx.session = _session
ngx.ctx.session_err = err
ngx.ctx.session_exists = exists
ngx.ctx.session_saved = false
ngx.ctx.session_data = _session.get_data()
if not ngx.ctx.session_data then
ngx.ctx.session_data = {}
end
return _session, err, exists
end
utils.save_session = function()
if ngx.ctx.session and not ngx.ctx.session_err and not ngx.ctx.session_saved then
ngx.ctx.session:set_data(ngx.ctx.session_data)
local ok, err = ngx.ctx.session:save()
if err then
logger.log(ngx.ERR, "UTILS", "can't save session : " .. err)
return false, "can't save session : " .. err
end
ngx.ctx.session_saved = true
return true, "session saved"
elseif ngx.ctx.session_saved then
return true, "session already saved"
end
return true, "no session"
end
utils.set_session = function(key, value)
if ngx.ctx.session and not ngx.ctx.session_err then
ngx.ctx.session_data[key] = value
return true, "value set"
end
return true, "no session"
end
utils.get_session = function(key)
if ngx.ctx.session and not ngx.ctx.session_err then
return true, "value set", ngx.ctx.session_data[key]
end
return false, "no session"
end
return utils

View File

@ -45,6 +45,7 @@ lua_package_cpath "/usr/share/bunkerweb/deps/lib/?.so;/usr/share/bunkerweb/deps/
lua_ssl_trusted_certificate "/usr/share/bunkerweb/misc/root-ca.pem";
lua_ssl_verify_depth 2;
lua_shared_dict datastore {{ DATASTORE_MEMORY_SIZE }};
lua_shared_dict datastore_ipc {{ DATASTORE_IPC_MEMORY_SIZE }};
# LUA init block
include /etc/nginx/init-lua.conf;

View File

@ -1,118 +1,166 @@
init_by_lua_block {
local logger = require "logger"
local datastore = require "datastore"
local plugins = require "plugins"
local utils = require "utils"
local cjson = require "cjson"
local class = require "middleclass"
local clogger = require "bunkerweb.logger"
local helpers = require "bunkerweb.helpers"
local datastore = require "bunkerweb.datastore"
logger.log(ngx.NOTICE, "INIT", "Init phase started")
-- Start init phase
logger:new("INIT")
datastore:new()
logger:log(ngx.NOTICE, "init phase started")
-- Remove previous data from the datastore
logger:log(ngx.NOTICE, "deleting old keys from datastore ...")
local data_keys = {"^plugin_", "^variable_", "^plugins$", "^api_", "^misc_"}
for i, key in pairs(data_keys) do
local ok, err = datastore:delete_all(key)
if not ok then
logger.log(ngx.ERR, "INIT", "Can't delete " .. key .. " from datastore : " .. err)
logger:log(ngx.ERR, "can't delete " .. key .. " from datastore : " .. err)
return false
end
logger.log(ngx.INFO, "INIT", "Deleted " .. key .. " from datastore")
logger:log(ngx.INFO, "deleted " .. key .. " from datastore")
end
logger:log(ngx.NOTICE, "deleted old keys from datastore")
-- Load variables into the datastore
logger:log(ngx.NOTICE, "saving variables into datastore ...")
local file = io.open("/etc/nginx/variables.env")
if not file then
logger.log(ngx.ERR, "INIT", "Can't open /etc/nginx/variables.env file")
logger:log(ngx.ERR, "can't open /etc/nginx/variables.env file")
return false
end
file:close()
for line in io.lines("/etc/nginx/variables.env") do
local variable, value = line:match("(.+)=(.*)")
ok, err = datastore:set("variable_" .. variable, value)
local ok, err = datastore:set("variable_" .. variable, value)
if not ok then
logger.log(ngx.ERR, "INIT", "Can't save variable " .. variable .. " into datastore")
logger:log(ngx.ERR, "can't save variable " .. variable .. " into datastore : " .. err)
return false
end
logger:log(ngx.INFO, "saved variable " .. variable .. "=" .. value .. " into datastore")
end
logger:log(ngx.NOTICE, "saved variables into datastore")
-- Set default values into the datastore
ok, err = datastore:set("plugins", cjson.encode({}))
if not ok then
logger.log(ngx.ERR, "INIT", "Can't set default value for plugins into the datastore : " .. err)
-- Set misc values into the datastore
logger:log(ngx.NOTICE, "saving misc values into datastore ...")
local miscs = {
reserved_ips = {
"0.0.0.0/8",
"10.0.0.0/8",
"100.64.0.0/10",
"127.0.0.0/8",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.88.99.0/24",
"192.168.0.0/16",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"224.0.0.0/4",
"233.252.0.0/24",
"240.0.0.0/4",
"255.255.255.255/32"
},
resolvers = {}
}
local var_resolvers, err = datastore:get("variable_DNS_RESOLVERS")
if not var_resolvers then
logger:log(ngx.ERR, "can't get variable DNS_RESOLVERS from datastore : " .. err)
return false
end
ok, err = utils.set_values()
if not ok then
logger.log(ngx.ERR, "INIT", "Error while setting default values : " .. err)
return false
for str_resolver in var_resolvers:gmatch("%S+") do
table.insert(miscs.resolvers, str_resolver)
end
for k, v in pairs(miscs) do
local ok, err = datastore:set("misc_" .. k, cjson.encode(v))
if not ok then
logger:log(ngx.ERR, "can't save misc " .. k .. " into datastore : " .. err)
return false
end
logger:log(ngx.INFO, "saved misc " .. k .. " into datastore")
end
logger:log(ngx.NOTICE, "saved misc values into datastore")
-- API setup
-- Set API values into the datastore
logger:log(ngx.NOTICE, "saving API values into datastore ...")
local value, err = datastore:get("variable_USE_API")
if not value then
logger.log(ngx.ERR, "INIT", "Can't get variable USE_API from the datastore")
logger.log(ngx.ERR, "can't get variable USE_API from the datastore : " .. err)
return false
end
if value == "yes" then
value, err = datastore:get("variable_API_WHITELIST_IP")
local value, err = datastore:get("variable_API_WHITELIST_IP")
if not value then
logger.log(ngx.ERR, "INIT", "Can't get variable API_WHITELIST_IP from the datastore")
logger.log(ngx.ERR, "can't get variable API_WHITELIST_IP from the datastore : " .. err)
return false
end
local whitelists = { data = {}}
local whitelists = {}
for whitelist in value:gmatch("%S+") do
table.insert(whitelists.data, whitelist)
table.insert(whitelists, whitelist)
end
ok, err = datastore:set("api_whitelist_ip", cjson.encode(whitelists))
local ok, err = datastore:set("api_whitelist_ip", cjson.encode(whitelists))
if not ok then
logger.log(ngx.ERR, "INIT", "Can't save api_whitelist_ip to datastore : " .. err)
logger.log(ngx.ERR, "can't save API whitelist_ip to datastore : " .. err)
return false
end
logger:log(ngx.INFO, "saved API whitelist_ip into datastore")
end
logger:log(ngx.NOTICE, "saved API values into datastore")
-- Load plugins into the datastore
logger:log(ngx.NOTICE, "saving plugins into datastore ...")
local plugins = {}
local plugin_paths = {"/usr/share/bunkerweb/core", "/etc/bunkerweb/plugins"}
for i, plugin_path in ipairs(plugin_paths) do
local paths = io.popen("find -L " .. plugin_path .. " -maxdepth 1 -type d ! -path " .. plugin_path)
for path in paths:lines() do
plugin, err = plugins:load(path)
if not plugin then
logger.log(ngx.ERR, "INIT", "Error while loading plugin from " .. path .. " : " .. err)
return false
local ok, plugin = helpers.load_plugin(path .. "/plugin.json")
if ok then
logger.log(ngx.ERR, err)
else
table.insert(plugins, plugin)
table.sort(plugins, function (a, b)
return a.order < b.order
end)
logger.log(ngx.NOTICE, "loaded plugin " .. plugin.id .. " v" .. plugin.version)
end
logger.log(ngx.NOTICE, "INIT", "Loaded plugin " .. plugin.id .. " v" .. plugin.version)
end
end
-- Call init method of plugins
local list, err = plugins:list()
if not list then
logger.log(ngx.ERR, "INIT", "Can't list loaded plugins : " .. err)
list = {}
local ok, err = datastore:set("plugins", cjson.encode(plugins))
if not ok then
logger.log(ngx.ERR, "can't save plugins into datastore : " .. err)
return false
end
for i, plugin in ipairs(list) do
local ret, plugin_lua = pcall(require, plugin.id .. "/" .. plugin.id)
if ret then
local plugin_obj = plugin_lua.new()
if plugin_obj.init ~= nil then
ok, err = plugin_obj:init()
if not ok then
logger.log(ngx.ERR, "INIT", "Plugin " .. plugin.id .. " failed on init() : " .. err)
else
logger.log(ngx.INFO, "INIT", "Successfull init() call for plugin " .. plugin.id .. " : " .. err)
end
else
logger.log(ngx.INFO, "INIT", "init() method not found in " .. plugin.id .. ", skipped execution")
end
logger:log(ngx.NOTICE, "saved plugins into datastore")
-- Call init() methods
logger:log(ngx.NOTICE, "calling init() methods of plugins ...")
for i, plugin in ipairs(plugins) do
local plugin_lua, err = helpers.new_plugin(plugin.id)
if plugin_lua == false then
logger.log(ngx.ERR, err)
else
if plugin_lua:match("not found") then
logger.log(ngx.INFO, "INIT", "can't require " .. plugin.id .. " : not found")
logger.log(ngx.NOTICE, err)
end
if plugin_lua ~= nil then
local ok, ret = helpers.call_plugin(plugin_lua)
if ok == false then
logger.log(ngx.ERR, ret)
elseif ok == nil then
logger.log(ngx.NOTICE, ret)
else
logger.log(ngx.ERR, "INIT", "can't require " .. plugin.id .. " : " .. plugin_lua)
if ret.ret then
logger.log(ngx.NOTICE, plugin.id .. ":init() call successful : " .. ret.msg)
else
logger.log(ngx.ERR, plugin.id .. ":init() call failed : " .. ret.msg)
end
end
end
end
logger:log(ngx.NOTICE, "called init() methods of plugins")
logger.log(ngx.NOTICE, "INIT", "Init phase ended")
logger:log(ngx.NOTICE, "init phase ended")
}

View File

@ -82,6 +82,14 @@ for i, plugin in ipairs(list) do
end
end
-- Save session
local ok, err = utils.save_session()
if not ok then
logger.log(ngx.ERR, "ACCESS", "Can't save session : " .. err)
else
logger.log(ngx.INFO, "ACCESS", "Session save status : " .. err)
end
logger.log(ngx.INFO, "ACCESS", "Access phase ended")
}

View File

@ -5,7 +5,6 @@ local utils = require "utils"
local datastore = require "datastore"
local logger = require "logger"
local cjson = require "cjson"
local session = require "resty.session"
local captcha = require "antibot.captcha"
local base64 = require "base64"
local sha256 = require "resty.sha256"
@ -59,6 +58,12 @@ function _M:access()
return false, "can't get Antibot URI from datastore : " .. err, nil, nil
end
-- Prepare challenge
local ok, err = self:prepare_challenge(antibot, challenge_uri)
if not ok then
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
-- Don't go further if client resolved the challenge
local resolved, err, original_uri = self:challenge_resolved(antibot)
if resolved == nil then
@ -73,10 +78,6 @@ function _M:access()
-- Redirect to challenge page
if ngx.var.uri ~= challenge_uri then
local ok, err = self:prepare_challenge(antibot, challenge_uri)
if not ok then
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
end
@ -84,13 +85,6 @@ function _M:access()
if ngx.var.request_method == "GET" then
local ok, err = self:display_challenge(antibot, challenge_uri)
if not ok then
if err == "can't open session" then
local ok, err = self:prepare_challenge(antibot, challenge_uri)
if not ok then
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
end
return false, "display challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "displaying challenge to client", true, ngx.HTTP_OK
@ -100,13 +94,6 @@ function _M:access()
if ngx.var.request_method == "POST" then
local ok, err, redirect = self:check_challenge(antibot)
if ok == nil then
if err == "can't open session" then
local ok, err = self:prepare_challenge(antibot, challenge_uri)
if not ok then
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
end
return false, "check challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
if redirect then
@ -114,13 +101,6 @@ function _M:access()
end
local ok, err = self:display_challenge(antibot)
if not ok then
if err == "can't open session" then
local ok, err = self:prepare_challenge(antibot, challenge_uri)
if not ok then
return false, "can't prepare challenge : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "redirecting client to the challenge uri", true, ngx.redirect(challenge_uri)
end
return false, "display challenge error : " .. err, true, ngx.HTTP_INTERNAL_SERVER_ERROR
end
return true, "displaying challenge to client", true, ngx.HTTP_OK
@ -131,63 +111,77 @@ function _M:access()
end
function _M:challenge_resolved(antibot)
local chall_session, present, reason = session.open()
if present and chall_session.data.resolved and chall_session.data.type == antibot then
return true, "challenge " .. antibot .. " resolved", chall_session.data.original_uri
local session, err, exists = utils.get_session()
if err then
return false, "session error : " .. err
end
return false, "challenge " .. antibot .. " not resolved", nil
local raw_data = get_session("antibot")
if not raw_data then
return false, "session is set but no antibot data", nil
end
local data = cjson.decode(raw_data)
if data.resolved and antibot == data.antibot then
return true, "challenge resolved", data.original_uri
end
return false, "challenge not resolved", data.original_uri
return false, "no session", nil
end
function _M:prepare_challenge(antibot, challenge_uri)
local chall_session, present, reason = session.open()
if not present then
local chall_session, present, reason = chall_session:start()
if not chall_session then
return false, "can't start session", nil
end
chall_session.data.type = antibot
chall_session.data.resolved = false
if ngx.var.request_uri == challenge_uri then
chall_session.data.original_uri = "/"
else
chall_session.data.original_uri = ngx.var.request_uri
end
if antibot == "cookie" then
chall_session.data.resolved = true
end
local saved, err = chall_session:save()
if not saved then
return false, "error while saving session : " .. err
local session, err, exists = utils.get_session()
if err then
return false, "session error : " .. err
end
local current_data = nil
if exists then
local raw_data = get_session("antibot")
if raw_data then
current_data = cjson.decode(raw_data)
end
end
return true, antibot .. " challenge prepared"
if not current_data or current_data.antibot ~= antibot then
local data = {
type = antibot,
resolved = antibot == "cookie",
original_uri = ngx.var.request_uri
}
if ngx.var.original_uri == challenge_uri then
data.original_uri = "/"
end
utils.set_session("antibot", cjson.encode(data))
return true, "prepared"
end
return true, "already prepared"
end
function _M:display_challenge(antibot, challenge_uri)
-- Open session
local chall_session, present, reason = session.open()
if not present then
return false, "can't open session"
local session, err, exists = utils.get_session()
if err then
return false, "can't open session : " .. err
end
-- Get data
local raw_data = get_session("antibot")
if not raw_data then
return false, "session is set but no data"
end
local data = cjson.decode(raw_data)
-- Check if session type is equal to antibot type
if antibot ~= chall_session.data.type then
if antibot ~= data.type then
return false, "session type is different from antibot type"
end
-- Compute challenges
if antibot == "javascript" then
chall_session:start()
chall_session.data.random = utils.rand(20)
chall_session:save()
data.random = utils.rand(20)
elseif antibot == "captcha" then
chall_session:start()
local chall_captcha = captcha.new()
chall_captcha:font("/usr/share/bunkerweb/core/antibot/files/font.ttf")
chall_captcha:generate()
chall_session.data.image = base64.encode(chall_captcha:jpegStr(70))
chall_session.data.text = chall_captcha:getStr()
chall_session:save()
data.image = base64.encode(chall_captcha:jpegStr(70))
data.text = chall_captcha:getStr()
end
-- Load HTML templates
@ -201,12 +195,12 @@ function _M:display_challenge(antibot, challenge_uri)
-- Javascript case
if antibot == "javascript" then
html = templates.javascript:format(challenge_uri, chall_session.data.random)
html = templates.javascript:format(challenge_uri, data.random)
end
-- Captcha case
if antibot == "captcha" then
html = templates.captcha:format(challenge_uri, chall_session.data.image)
html = templates.captcha:format(challenge_uri, data.image)
end
-- reCAPTCHA case
@ -227,6 +221,12 @@ function _M:display_challenge(antibot, challenge_uri)
html = templates.hcaptcha:format(challenge_uri, hcaptcha_sitekey)
end
-- Set new data
utils.set_session("antibot", cjson.encode(data))
local ok, err = utils.save_session()
if not ok then
return false, "can't save session : " .. err
end
ngx.header["Content-Type"] = "text/html"
ngx.say(html)
@ -235,13 +235,20 @@ end
function _M:check_challenge(antibot)
-- Open session
local chall_session, present, reason = session.open()
if not present then
return nil, "can't open session", nil
local session, err, exists = utils.get_session()
if err then
return nil, "can't open session : " .. err, nil
end
-- Get data
local raw_data = get_session("antibot")
if not raw_data then
return false, "session is set but no data", nil
end
local data = cjson.decode(raw_data)
-- Check if session type is equal to antibot type
if antibot ~= chall_session.data.type then
if antibot ~= data.type then
return nil, "session type is different from antibot type", nil
end
@ -257,16 +264,15 @@ function _M:check_challenge(antibot)
return false, "missing challenge arg", nil
end
local hash = sha256:new()
hash:update(chall_session.data.random .. args["challenge"])
hash:update(data.random .. args["challenge"])
local digest = hash:final()
resolved = str.to_hex(digest):find("^0000") ~= nil
if not resolved then
return false, "wrong value", nil
end
chall_session:start()
chall_session.data.resolved = true
chall_session:save()
return true, "resolved", chall_session.data.original_uri
data.resolved = true
utils.set_session("antibot", cjson.encode(data))
return true, "resolved", data.original_uri
end
-- Captcha case
@ -276,13 +282,12 @@ function _M:check_challenge(antibot)
if err == "truncated" or not args or not args["captcha"] then
return false, "missing challenge arg", nil
end
if chall_session.data.text ~= args["captcha"] then
if data.text ~= args["captcha"] then
return false, "wrong value", nil
end
chall_session:start()
chall_session.data.resolved = true
chall_session:save()
return true, "resolved", chall_session.data.original_uri
data.resolved = true
utils.set_session("antibot", cjson.encode(data))
return true, "resolved", data.original_uri
end
-- reCAPTCHA case
@ -311,21 +316,20 @@ function _M:check_challenge(antibot)
if not res then
return nil, "can't send request to reCAPTCHA API : " .. err, nil
end
local ok, data = pcall(cjson.decode, res.body)
local ok, rdata = pcall(cjson.decode, res.body)
if not ok then
return nil, "error while decoding JSON from reCAPTCHA API : " .. data, nil
return nil, "error while decoding JSON from reCAPTCHA API : " .. rdata, nil
end
local recaptcha_score, err = utils.get_variable("ANTIBOT_RECAPTCHA_SCORE")
if not recaptcha_score then
return nil, "can't get reCAPTCHA score variable : " .. err, nil
end
if not data.success or data.score < tonumber(recaptcha_score) then
return false, "client failed challenge with score " .. tostring(data.score), nil
if not rdata.success or rdata.score < tonumber(recaptcha_score) then
return false, "client failed challenge with score " .. tostring(rdata.score), nil
end
chall_session:start()
chall_session.data.resolved = true
chall_session:save()
return true, "resolved", chall_session.data.original_uri
data.resolved = true
utils.set_session("antibot", cjson.encode(data))
return true, "resolved", data.original_uri
end
-- hCaptcha case
@ -354,17 +358,16 @@ function _M:check_challenge(antibot)
if not res then
return nil, "can't send request to hCaptcha API : " .. err, nil
end
local ok, data = pcall(cjson.decode, res.body)
local ok, hdata = pcall(cjson.decode, res.body)
if not ok then
return nil, "error while decoding JSON from hCaptcha API : " .. data, nil
end
if not data.success then
if not hdata.success then
return false, "client failed challenge", nil
end
chall_session:start()
chall_session.data.resolved = true
chall_session:save()
return true, "resolved", chall_session.data.original_uri
data.resolved = true
utils.set_session("antibot", cjson.encode(data))
return true, "resolved", data.original_uri
end
return nil, "unknown", nil

View File

@ -0,0 +1,4 @@
local _M = {}
local mlcache = require "resty.mlcache"

View File

@ -0,0 +1,22 @@
local class = require "bunkerweb.middleclass"
local logger = require "bunkerweb.logger"
local settings = require "bunkerweb.settings"
local plugin = class("plugin")
function plugin:initialize(name, fill_settings)
self.name = name
self.logger = logger:new(name)
self.settings = {}
for i, setting in ipairs(fill_settings) do
local value, err = settings:get(setting)
if not value then
local err = string.format("can't get setting %s : %s", setting, err)
self.logger:log(ngx.ERR, err)
return false, err
end
self.settings[setting] = value
end
return true, nil
end
return plugin

View File

@ -1,52 +1,52 @@
{
"id": "session",
"id": "sessions",
"order": 999,
"name": "Session",
"name": "Sessions",
"description": "Management of session used by other plugins.",
"version": "0.1",
"settings": {
"SESSION_SECRET": {
"SESSIONS_SECRET": {
"context": "global",
"default": "random",
"help": "Secret used to encrypt sessions variables for storing data related to challenges.",
"id": "session-secret",
"label": "Session secret",
"label": "Sessions secret",
"regex": "^\\w+$",
"type": "password"
},
"SESSION_NAME": {
"SESSIONS_NAME": {
"context": "global",
"default": "random",
"help": "Name of the cookie given to clients.",
"id": "session-name",
"label": "Session name",
"id": "sessions-name",
"label": "Sessions name",
"regex": "^\\w+$",
"type": "text"
},
"SESSION_IDLING_TIMEOUT": {
"SESSIONS_IDLING_TIMEOUT": {
"context": "global",
"default": "1800",
"help": "Maximum time (in seconds) of inactivity before the session is invalidated.",
"id": "session-idling-timeout",
"label": "Session idling timeout",
"id": "sessions-idling-timeout",
"label": "Sessions idling timeout",
"regex": "^\\d+$",
"type": "text"
},
"SESSION_ROLLING_TIMEOUT": {
"SESSIONS_ROLLING_TIMEOUT": {
"context": "global",
"default": "3600",
"help": "Maximum time (in seconds) before a session must be renewed.",
"id": "session-rolling-timeout",
"label": "Session rolling timeout",
"id": "sessions-rolling-timeout",
"label": "Sessions rolling timeout",
"regex": "^\\d+$",
"type": "text"
},
"SESSION_ABSOLUTE_TIMEOUT": {
"SESSIONS_ABSOLUTE_TIMEOUT": {
"context": "global",
"default": "86400",
"help": "Maximum time (in seconds) before a session is destroyed.",
"id": "session-absolute-timeout",
"label": "Session absolute timeout",
"id": "sessions-absolute-timeout",
"label": "SessionS absolute timeout",
"regex": "^\\d+$",
"type": "text"
}

View File

@ -12,11 +12,11 @@ end
function _M:init()
-- Get vars
local vars = {
["SESSION_SECRET"] = "",
["SESSION_NAME"] = "",
["SESSION_IDLING_TIMEOUT"] = "",
["SESSION_ROLLING_TIMEOUT"] = "",
["SESSION_ABSOLUTE_TIMEOUT"] = "",
["SESSIONS_SECRET"] = "",
["SESSIONS_NAME"] = "",
["SESSIONS_IDLING_TIMEOUT"] = "",
["SESSIONS_ROLLING_TIMEOUT"] = "",
["SESSIONS_ABSOLUTE_TIMEOUT"] = "",
["USE_REDIS"] = "",
["REDIS_HOST"] = "",
["REDIS_PORT"] = "",
@ -33,16 +33,16 @@ function _M:init()
end
-- Init configuration
local config = {
secret = vars["SESSION_SECRET"],
cookie_name = vars["SESSION_NAME"],
idling_timeout = tonumber(vars["SESSION_IDLING_TIMEOUT"]),
rolling_timeout = tonumber(vars["SESSION_ROLLING_TIMEOUT"]),
absolute_timeout = tonumber(vars["SESSION_ABSOLUTE_TIMEOUT"])
secret = vars["SESSIONS_SECRET"],
cookie_name = vars["SESSIONS_NAME"],
idling_timeout = tonumber(vars["SESSIONS_IDLING_TIMEOUT"]),
rolling_timeout = tonumber(vars["SESSIONS_ROLLING_TIMEOUT"]),
absolute_timeout = tonumber(vars["SESSIONS_ABSOLUTE_TIMEOUT"])
}
if vars["SESSION_SECRET"] == "random" then
if vars["SESSIONS_SECRET"] == "random" then
config.secret = utils.rand(16)
end
if vars["SESSION_NAME"] == "random" then
if vars["SESSIONS_NAME"] == "random" then
config.cookie_name = utils.rand(16)
end
if vars["USE_REDIS"] == "no" then
@ -64,24 +64,7 @@ function _M:init()
}
end
session.init(config)
return true, "session init successful"
end
function _M:access()
-- Start session and refresh it if needed
local client_session, err, exists, refreshed = session.start()
if err then
return false, "can't open session : " .. err, nil, nil
end
-- Refresh it
if exists then
local ok, err = client_session:refresh()
if err then
return false, "can't refresh session : " .. err, nil, nil
end
return true, "session exists", nil, nil
end
return true, "session doesn't exist", nil, nil
return true, "sessions init successful"
end
return _M