mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
refactor of session management
This commit is contained in:
parent
0fdb108fe9
commit
a5e08e1c67
9 changed files with 97 additions and 138 deletions
2
TODO
2
TODO
|
|
@ -1,6 +1,4 @@
|
|||
- utils refactoring
|
||||
- load inline values for white/black/grey list core
|
||||
- check if correct setting is set to yes in new() before loading stuff in self
|
||||
- store object in ngx.ctx
|
||||
- bwcli with redis
|
||||
- move bans to cachestore
|
||||
|
|
|
|||
|
|
@ -433,55 +433,59 @@ end
|
|||
utils.get_session = function()
|
||||
-- Session already in context
|
||||
if ngx.ctx.bw.session then
|
||||
return ngx.ctx.bw.session, ngx.ctx.bw.session_err, ngx.ctx.bw.session_exists
|
||||
return ngx.ctx.bw.session, ngx.ctx.bw.session_err, ngx.ctx.bw.session_exists, ngx.ctx.bw.session_refreshed
|
||||
end
|
||||
-- Open session
|
||||
local _session, err, exists = session.start()
|
||||
if err then
|
||||
-- Open session and fill ctx
|
||||
local _session, err, exists, refreshed = session.start()
|
||||
ngx.ctx.bw.session_err = nil
|
||||
if err and err ~= "missing session cookie" and err ~= "no session" then
|
||||
logger:log(ngx.ERR, "can't start session : " .. err)
|
||||
ngx.ctx.bw.session_err = nil
|
||||
end
|
||||
-- Fill ctx
|
||||
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 = {}
|
||||
ngx.ctx.bw.session = _session
|
||||
ngx.ctx.bw.session_exists = exists
|
||||
ngx.ctx.bw.session_refreshed = refreshed
|
||||
ngx.ctx.bw.session_saved = false
|
||||
ngx.ctx.bw.session_data = _session:get_data()
|
||||
if not ngx.ctx.bw.session_data then
|
||||
ngx.ctx.bw.session_data = {}
|
||||
end
|
||||
return _session, err, exists
|
||||
return _session, ngx.ctx.bw.session_err, exists, refreshed
|
||||
end
|
||||
|
||||
utils.save_session = function()
|
||||
-- Check if save is needed
|
||||
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 ngx.ctx.bw.session and not ngx.ctx.bw.session_err and not ngx.ctx.bw.session_saved then
|
||||
ngx.ctx.bw.session:set_data(ngx.ctx.bw.session_data)
|
||||
local ok, err = ngx.ctx.bw.session:save()
|
||||
if err then
|
||||
logger:log(ngx.ERR, "can't save session : " .. err)
|
||||
return false, "can't save session : " .. err
|
||||
end
|
||||
ngx.ctx.session_saved = true
|
||||
ngx.ctx.bw.session_saved = true
|
||||
return true, "session saved"
|
||||
elseif ngx.ctx.session_saved then
|
||||
elseif ngx.ctx.bw.session_saved then
|
||||
return true, "session already saved"
|
||||
end
|
||||
return true, "no session"
|
||||
end
|
||||
|
||||
utils.set_session = function(key, value)
|
||||
utils.set_session_var = function(key, value)
|
||||
-- Set new data
|
||||
if ngx.ctx.session and not ngx.ctx.session_err then
|
||||
ngx.ctx.session_data[key] = value
|
||||
if ngx.ctx.bw.session and not ngx.ctx.bw.session_err then
|
||||
ngx.ctx.bw.session_data[key] = value
|
||||
return true, "value set"
|
||||
end
|
||||
return true, "no session"
|
||||
return false, "no session"
|
||||
end
|
||||
|
||||
utils.get_session = function(key)
|
||||
utils.get_session_var = function(key)
|
||||
-- Get data
|
||||
if ngx.ctx.session and not ngx.ctx.session_err then
|
||||
return true, "value get", ngx.ctx.session_data[key]
|
||||
if ngx.ctx.bw.session and not ngx.ctx.bw.session_err then
|
||||
if ngx.ctx.bw.session_data[key] then
|
||||
return true, "data present", ngx.ctx.bw.session_data[key]
|
||||
end
|
||||
return true, "no data"
|
||||
end
|
||||
return false, "no session"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
local datastore = require "datastore"
|
||||
local cjson = require "cjson"
|
||||
|
||||
local plugins = {}
|
||||
|
||||
plugins.load = function(self, path)
|
||||
-- Read plugin.json file
|
||||
local file = io.open(path .. "/plugin.json")
|
||||
if not file then
|
||||
return false, "can't read plugin.json file"
|
||||
end
|
||||
|
||||
-- Decode plugin.json
|
||||
-- TODO : check return value of file:read and cjson.encode
|
||||
local data = cjson.decode(file:read("*a"))
|
||||
file:close()
|
||||
|
||||
-- Check required fields
|
||||
local required_fields = {"id", "order", "name", "description", "version", "settings"}
|
||||
for i, field in ipairs(required_fields) do
|
||||
if data[field] == nil then
|
||||
return false, "missing field " .. field .. " in plugin.json"
|
||||
end
|
||||
-- TODO : check values and types with regex
|
||||
end
|
||||
|
||||
-- Get existing plugins
|
||||
local list, err = plugins:list()
|
||||
if not list then
|
||||
return false, err
|
||||
end
|
||||
|
||||
-- Add our plugin to existing list and sort it
|
||||
table.insert(list, data)
|
||||
table.sort(list, function (a, b)
|
||||
return a.order < b.order
|
||||
end)
|
||||
|
||||
-- Save new plugin list in datastore
|
||||
local ok, err = datastore:set("plugins", cjson.encode(list))
|
||||
if not ok then
|
||||
return false, "can't save new plugin list"
|
||||
end
|
||||
|
||||
-- Save default settings value
|
||||
for variable, value in pairs(data.settings) do
|
||||
ok, err = datastore:set("plugin_" .. data.id .. "_" .. variable, value["default"])
|
||||
if not ok then
|
||||
return false, "can't save default variable value of " .. variable .. " into datastore"
|
||||
end
|
||||
end
|
||||
|
||||
-- Return the plugin
|
||||
return data, "success"
|
||||
end
|
||||
|
||||
plugins.list = function(self)
|
||||
-- Get encoded plugins from datastore
|
||||
local encoded_plugins, err = datastore:get("plugins")
|
||||
if not encoded_plugins then
|
||||
return false, "can't get encoded plugins from datastore"
|
||||
end
|
||||
|
||||
-- Decode and return the list
|
||||
return cjson.decode(encoded_plugins), "success"
|
||||
end
|
||||
|
||||
return plugins
|
||||
|
|
@ -49,6 +49,8 @@ plugins = cjson.decode(plugins)
|
|||
|
||||
-- Call access() methods
|
||||
logger:log(ngx.INFO, "calling access() methods of plugins ...")
|
||||
local status = nil
|
||||
local redirect = nil
|
||||
for i, plugin in ipairs(plugins) do
|
||||
-- Require call
|
||||
local plugin_lua, err = helpers.require_plugin(plugin.id)
|
||||
|
|
@ -75,15 +77,15 @@ for i, plugin in ipairs(plugins) do
|
|||
if ret.status then
|
||||
if ret.status == utils.get_deny_status() then
|
||||
ngx.ctx.reason = plugin.id
|
||||
logger:log(ngx.WARN, "denied access from " .. plugin.id .. " : " .. err)
|
||||
logger:log(ngx.WARN, "denied access from " .. plugin.id .. " : " .. ret.msg)
|
||||
else
|
||||
logger:log(ngx.NOTICE, plugin.id .. " returned status " .. tostring(ret.status))
|
||||
logger:log(ngx.NOTICE, plugin.id .. " returned status " .. tostring(ret.status) .. " : " .. ret.msg)
|
||||
end
|
||||
ngx.ctx.status = ret.status
|
||||
status = ret.status
|
||||
break
|
||||
elseif ret.redirect then
|
||||
logger:log(ngx.NOTICE, plugin.id .. " redirect to " .. ret.redirect .. " : " .. err)
|
||||
ngx.ctx.redirect = ret.redirect
|
||||
logger:log(ngx.NOTICE, plugin.id .. " redirect to " .. ret.redirect .. " : " .. ret.msg)
|
||||
redirect = ret.redirect
|
||||
break
|
||||
end
|
||||
end
|
||||
|
|
@ -103,13 +105,13 @@ end
|
|||
logger:log(ngx.INFO, "access phase ended")
|
||||
|
||||
-- Return status if needed
|
||||
if ngx.ctx.status then
|
||||
return ngx.exit(ngx.ctx.status)
|
||||
if status then
|
||||
return ngx.exit(status)
|
||||
end
|
||||
|
||||
-- Redirect if needed
|
||||
if ngx.ctx.redirect then
|
||||
return ngx.redirect(ngx.ctx.redirect)
|
||||
if redirect then
|
||||
return ngx.redirect(redirect)
|
||||
end
|
||||
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ for i, plugin in ipairs(plugins) do
|
|||
elseif not ret.ret then
|
||||
logger:log(ngx.ERR, plugin.id .. ":header() call failed : " .. ret.msg)
|
||||
else
|
||||
logger:log(ngx.NOTICE, plugin.id .. ":header() call successful : " .. ret.msg)
|
||||
logger:log(ngx.INFO, plugin.id .. ":header() call successful : " .. ret.msg)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function antibot:access()
|
|||
end
|
||||
|
||||
-- Prepare challenge
|
||||
local ok, err = self:prepare_challenge(antibot, challenge_uri)
|
||||
local ok, err = self:prepare_challenge(antibot, self.variables["ANTIBOT_URI"])
|
||||
if not ok then
|
||||
return self:ret(false, "can't prepare challenge : " .. err, ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||
end
|
||||
|
|
@ -35,20 +35,20 @@ function antibot:access()
|
|||
return self:ret(false, "can't check if challenge is resolved : " .. err)
|
||||
end
|
||||
if resolved then
|
||||
if ngx.ctx.bw.uri == challenge_uri then
|
||||
if ngx.ctx.bw.uri == self.variables["ANTIBOT_URI"] then
|
||||
return self:ret(true, "client already resolved the challenge", nil, original_uri)
|
||||
end
|
||||
return self:ret(true, "client already resolved the challenge")
|
||||
end
|
||||
|
||||
-- Redirect to challenge page
|
||||
if ngx.ctx.bw.uri ~= challenge_uri then
|
||||
return self:ret(true, "redirecting client to the challenge uri", nil, challenge_uri)
|
||||
if ngx.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then
|
||||
return self:ret(true, "redirecting client to the challenge uri", nil, self.variables["ANTIBOT_URI"])
|
||||
end
|
||||
|
||||
-- Display challenge needed
|
||||
if ngx.ctx.bw.request_method == "GET" then
|
||||
ngx.ctx.antibot_display_content = true
|
||||
ngx.ctx.bw.antibot_display_content = true
|
||||
return self:ret(true, "displaying challenge to client", ngx.HTTP_OK)
|
||||
end
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ function antibot:access()
|
|||
if redirect then
|
||||
return self:ret(true, "check challenge redirect : " .. redirect, nil, redirect)
|
||||
end
|
||||
ngx.ctx.antibot_display_content = true
|
||||
ngx.ctx.bw.antibot_display_content = true
|
||||
return self:ret(true, "displaying challenge to client", ngx.HTTP_OK)
|
||||
end
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ function antibot:content()
|
|||
return self:ret(true, "antibot not activated")
|
||||
end
|
||||
-- Check if display content is needed
|
||||
if not ngx.ctx.antibot_display_content then
|
||||
if not ngx.ctx.bw.antibot_display_content then
|
||||
return self:ret(true, "display content not needed")
|
||||
end
|
||||
-- Display content
|
||||
|
|
@ -91,13 +91,15 @@ function antibot:content()
|
|||
end
|
||||
|
||||
function antibot:challenge_resolved()
|
||||
local session, err, exists = utils.get_session()
|
||||
local session, err, exists, refreshed = utils.get_session()
|
||||
if err then
|
||||
return false, "session error : " .. err
|
||||
return nil, "session error : " .. err
|
||||
elseif not exists then
|
||||
return false, "no session set"
|
||||
end
|
||||
local raw_data = get_session("antibot")
|
||||
local ok, err, raw_data = utils.get_session_var("antibot")
|
||||
if not raw_data then
|
||||
return false, "session is set but no antibot data", nil
|
||||
return nil, "session is set but no antibot data", nil
|
||||
end
|
||||
local data = cjson.decode(raw_data)
|
||||
if data.resolved and self.variables["USE_ANTIBOT"] == data.antibot then
|
||||
|
|
@ -107,19 +109,19 @@ function antibot:challenge_resolved()
|
|||
end
|
||||
|
||||
function antibot:prepare_challenge()
|
||||
local session, err, exists = utils.get_session()
|
||||
local session, err, exists, refreshed = utils.get_session()
|
||||
if err then
|
||||
return false, "session error : " .. err
|
||||
end
|
||||
local set_needed = false
|
||||
local data = nil
|
||||
if exists then
|
||||
local raw_data = get_session("antibot")
|
||||
local ok, err, raw_data = utils.get_session_var("antibot")
|
||||
if raw_data then
|
||||
data = cjson.decode(raw_data)
|
||||
end
|
||||
end
|
||||
if not data or current_data.antibot ~= self.variables["USE_ANTIBOT"] then
|
||||
if not data or data.antibot ~= self.variables["USE_ANTIBOT"] then
|
||||
data = {
|
||||
type = self.variables["USE_ANTIBOT"],
|
||||
resolved = self.variables["USE_ANTIBOT"] == "cookie",
|
||||
|
|
@ -144,20 +146,25 @@ function antibot:prepare_challenge()
|
|||
end
|
||||
end
|
||||
if set_needed then
|
||||
utils.set_session("antibot", cjson.encode(data))
|
||||
local ok, err = utils.set_session_var("antibot", cjson.encode(data))
|
||||
if not ok then
|
||||
return false, "error while setting session antibot : " .. err
|
||||
end
|
||||
end
|
||||
return true, "prepared"
|
||||
end
|
||||
|
||||
function antibot:display_challenge(challenge_uri)
|
||||
-- Open session
|
||||
local session, err, exists = utils.get_session()
|
||||
local session, err, exists, refreshed = utils.get_session()
|
||||
if err then
|
||||
return false, "can't open session : " .. err
|
||||
elseif not exists then
|
||||
return false, "no session set"
|
||||
end
|
||||
|
||||
-- Get data
|
||||
local raw_data = get_session("antibot")
|
||||
local ok, err, raw_data = utils.get_session_var("antibot")
|
||||
if not raw_data then
|
||||
return false, "session is set but no data"
|
||||
end
|
||||
|
|
@ -201,13 +208,15 @@ end
|
|||
|
||||
function antibot:check_challenge()
|
||||
-- Open session
|
||||
local session, err, exists = utils.get_session()
|
||||
local session, err, exists, refreshed = utils.get_session()
|
||||
if err then
|
||||
return nil, "can't open session : " .. err, nil
|
||||
elseif not exists then
|
||||
return false, "no session set"
|
||||
end
|
||||
|
||||
-- Get data
|
||||
local raw_data = get_session("antibot")
|
||||
local ok, err, raw_data = utils.get_session_var("antibot")
|
||||
if not raw_data then
|
||||
return false, "session is set but no data", nil
|
||||
end
|
||||
|
|
@ -237,7 +246,10 @@ function antibot:check_challenge()
|
|||
return false, "wrong value", nil
|
||||
end
|
||||
data.resolved = true
|
||||
utils.set_session("antibot", cjson.encode(data))
|
||||
local ok, err = utils.set_session("antibot", cjson.encode(data))
|
||||
if not ok then
|
||||
return false, "error while setting session antibot : " .. err
|
||||
end
|
||||
return true, "resolved", data.original_uri
|
||||
end
|
||||
|
||||
|
|
@ -252,7 +264,10 @@ function antibot:check_challenge()
|
|||
return false, "wrong value", nil
|
||||
end
|
||||
data.resolved = true
|
||||
utils.set_session("antibot", cjson.encode(data))
|
||||
local ok, err = utils.set_session("antibot", cjson.encode(data))
|
||||
if not ok then
|
||||
return false, "error while setting session antibot : " .. err
|
||||
end
|
||||
return true, "resolved", data.original_uri
|
||||
end
|
||||
|
||||
|
|
@ -286,7 +301,10 @@ function antibot:check_challenge()
|
|||
return false, "client failed challenge with score " .. tostring(rdata.score), nil
|
||||
end
|
||||
data.resolved = true
|
||||
utils.set_session("antibot", cjson.encode(data))
|
||||
local ok, err = utils.set_session("antibot", cjson.encode(data))
|
||||
if not ok then
|
||||
return false, "error while setting session antibot : " .. err
|
||||
end
|
||||
return true, "resolved", data.original_uri
|
||||
end
|
||||
|
||||
|
|
@ -320,7 +338,10 @@ function antibot:check_challenge()
|
|||
return false, "client failed challenge", nil
|
||||
end
|
||||
data.resolved = true
|
||||
utils.set_session("antibot", cjson.encode(data))
|
||||
local ok, err = utils.set_session("antibot", cjson.encode(data))
|
||||
if not ok then
|
||||
return false, "error while setting session antibot : " .. err
|
||||
end
|
||||
return true, "resolved", data.original_uri
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{% if USE_ANTIBOT == "yes" +%}
|
||||
{% if USE_ANTIBOT != "no" +%}
|
||||
location /{{ ANTIBOT_URI }} {
|
||||
default_type 'text/html';
|
||||
root /usr/share/bunkerweb/core/antibot/files;
|
||||
content_by_lua_block {
|
||||
local cantibot = require "antibot.antibot"
|
||||
|
|
|
|||
|
|
@ -4,24 +4,24 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Bot Detection</title>
|
||||
<link rel="icon" href="data:image/svg+xml, %%3Csvg version='1.0' xmlns='http://www.w3.org/2000/svg' width='96.000000pt' height='96.000000pt' viewBox='0 0 96.000000 96.000000' preserveAspectRatio='xMidYMid meet'%%3E%%3Cg transform='translate(0.000000,96.000000) scale(0.100000,-0.100000)'%%0Afill='%%23085577' stroke='none'%%3E%%3Cpath d='M535 863 c-22 -2 -139 -17 -260 -34 -228 -31 -267 -43 -272 -85 -2%%0A-10 23 -181 55 -379 l57 -360 400 0 400 0 20 40 c16 31 20 59 19 125 -1 100%%0A-24 165 -73 199 -41 29 -46 57 -22 111 30 67 29 188 -3 256 -13 28 -37 60 -53%%0A72 -55 39 -169 62 -268 55z m-15 -348 c30 -16 60 -61 60 -90 0 -10 -8 -33 -17%%0A-52 -16 -34 -16 -41 0 -116 9 -44 15 -82 12 -85 -6 -7 -92 -21 -131 -21 l-31%%0A-1 -6 85 c-4 75 -8 89 -31 112 -20 20 -26 36 -26 70 0 38 5 50 34 79 39 39 86%%0A45 136 19z'/%%3E%%3C/g%%3E%%3C/svg%%3E" type="image/svg+xml"/>
|
||||
<link rel="icon" href="data:image/svg+xml, %3Csvg version='1.0' xmlns='http://www.w3.org/2000/svg' width='96.000000pt' height='96.000000pt' viewBox='0 0 96.000000 96.000000' preserveAspectRatio='xMidYMid meet'%3E%3Cg transform='translate(0.000000,96.000000) scale(0.100000,-0.100000)'%0Afill='%23085577' stroke='none'%3E%3Cpath d='M535 863 c-22 -2 -139 -17 -260 -34 -228 -31 -267 -43 -272 -85 -2%0A-10 23 -181 55 -379 l57 -360 400 0 400 0 20 40 c16 31 20 59 19 125 -1 100%0A-24 165 -73 199 -41 29 -46 57 -22 111 30 67 29 188 -3 256 -13 28 -37 60 -53%0A72 -55 39 -169 62 -268 55z m-15 -348 c30 -16 60 -61 60 -90 0 -10 -8 -33 -17%0A-52 -16 -34 -16 -41 0 -116 9 -44 15 -82 12 -85 -6 -7 -92 -21 -131 -21 l-31%0A-1 -6 85 c-4 75 -8 89 -31 112 -20 20 -26 36 -26 70 0 38 5 50 34 79 39 39 86%0A45 136 19z'/%3E%3C/g%3E%3C/svg%3E" type="image/svg+xml"/>
|
||||
<style type="text/css">
|
||||
body,
|
||||
html {
|
||||
width: 100%%;
|
||||
height: 100%%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #125678;
|
||||
}
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
min-height: 100%%;
|
||||
min-height: 100%;
|
||||
display: table;
|
||||
font-family: "Open Sans", Arial, sans-serif;
|
||||
margin: 0;
|
||||
-ms-text-size-adjust: 100%%;
|
||||
-webkit-text-size-adjust: 100%%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
h1 {
|
||||
display: flex;
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
}
|
||||
footer {
|
||||
position: fixed;
|
||||
width: 100%%;
|
||||
width: 100%;
|
||||
letter-spacing: 1px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
|
@ -130,8 +130,8 @@
|
|||
<div class="cover message">
|
||||
<h1>Please prove that you are Human before accessing this website</h1>
|
||||
<p class="lead">
|
||||
<form class="form" method="POST" action="%s">
|
||||
<img src="data:image/jpeg;base64,%s"/>
|
||||
<form class="form" method="POST" action="{{antibot_uri}}">
|
||||
<img src="data:image/jpeg;base64,{{captcha}}"/>
|
||||
<input class="captcha" type="text" name="captcha" /> <input class="btn" type="submit" value="Submit" />
|
||||
</form>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-pack" do_and_check_cmd make INST_LIBDIR=
|
|||
# Installing lua-resty-openssl
|
||||
echo "ℹ️ Installing lua-resty-openssl"
|
||||
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-openssl" do_and_check_cmd make LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
|
||||
do_and_check_cmd cp /tmp/bunkerweb/deps/src/lua-resty-openssl/lib/resty/openssl.lua /usr/share/bunkerweb/deps/lib/lua/resty
|
||||
|
||||
# Compile dynamic modules
|
||||
echo "ℹ️ Compiling and installing dynamic modules"
|
||||
|
|
|
|||
Loading…
Reference in a new issue