Lint Lua code

This commit is contained in:
Théophile Diot 2023-05-16 11:37:43 -04:00
parent 36fdec1058
commit 8386621419
No known key found for this signature in database
GPG key ID: E752C80DB72BB014
24 changed files with 471 additions and 429 deletions

View file

@ -1,13 +1,12 @@
local class = require "middleclass" local class = require "middleclass"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cjson = require "cjson" local cjson = require "cjson"
local upload = require "resty.upload" local upload = require "resty.upload"
local api = class("api") local api = class("api")
api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} } api.global = { GET = {}, POST = {}, PUT = {}, DELETE = {} }
function api:initialize() function api:initialize()
self.datastore = datastore:new() self.datastore = datastore:new()

View file

@ -1,19 +1,19 @@
local mlcache = require "resty.mlcache" local mlcache = require "resty.mlcache"
local logger = require "bunkerweb.logger" local logger = require "bunkerweb.logger"
local class = require "middleclass" local class = require "middleclass"
local cachestore = class("cachestore") local cachestore = class("cachestore")
-- Instantiate mlcache object at module level (which will be cached when running init phase) -- Instantiate mlcache object at module level (which will be cached when running init phase)
-- TODO : custom settings -- TODO : custom settings
local shm = "cachestore" local shm = "cachestore"
local ipc_shm = "cachestore_ipc" local ipc_shm = "cachestore_ipc"
local shm_miss = "cachestore_miss" local shm_miss = "cachestore_miss"
local shm_locks = "cachestore_locks" local shm_locks = "cachestore_locks"
if not ngx.shared.cachestore then if not ngx.shared.cachestore then
shm = "cachestore_stream" shm = "cachestore_stream"
ipc_shm = "cachestore_ipc_stream" ipc_shm = "cachestore_ipc_stream"
shm_miss = "cachestore_miss_stream" shm_miss = "cachestore_miss_stream"
shm_locks = "cachestore_locks_stream" shm_locks = "cachestore_locks_stream"
end end
local cache, err = mlcache.new( local cache, err = mlcache.new(
"cachestore", "cachestore",
@ -108,7 +108,7 @@ function cachestore:set(key, value, ex)
end end
local ok, err local ok, err
if ex then if ex then
ok, err = self.cache:set(key, {ttl = ex}, value) ok, err = self.cache:set(key, { ttl = ex }, value)
else else
ok, err = self.cache:set(key, nil, value) ok, err = self.cache:set(key, nil, value)
end end

View file

@ -1,7 +1,7 @@
local class = require "middleclass" local class = require "middleclass"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local logger = require "bunkerweb.logger" local logger = require "bunkerweb.logger"
local redis = require "resty.redis" local redis = require "resty.redis"
local clusterstore = class("clusterstore") local clusterstore = class("clusterstore")
@ -42,7 +42,8 @@ function clusterstore:connect()
return false, err return false, err
end end
-- Set timeouts -- Set timeouts
redis_client:set_timeouts(tonumber(self.variables["REDIS_TIMEOUT"]), tonumber(self.variables["REDIS_TIMEOUT"]), tonumber(self.variables["REDIS_TIMEOUT"])) redis_client:set_timeouts(tonumber(self.variables["REDIS_TIMEOUT"]), tonumber(self.variables["REDIS_TIMEOUT"]),
tonumber(self.variables["REDIS_TIMEOUT"]))
-- Connect -- Connect
local options = { local options = {
ssl = self.variables["REDIS_SSL"] == "yes", ssl = self.variables["REDIS_SSL"] == "yes",
@ -74,7 +75,8 @@ end
function clusterstore:close() function clusterstore:close()
if self.redis_client then if self.redis_client then
-- Equivalent to close but keep a pool of connections -- Equivalent to close but keep a pool of connections
local ok, err = self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]), tonumber(self.variables["REDIS_KEEPALIVE_POOL"])) local ok, err = self.redis_client:set_keepalive(tonumber(self.variables["REDIS_KEEPALIVE_IDLE"]),
tonumber(self.variables["REDIS_KEEPALIVE_POOL"]))
self.redis_client = nil self.redis_client = nil
return ok, err return ok, err
end end
@ -120,4 +122,4 @@ function clusterstore:multi(calls)
return true, "success", exec return true, "success", exec
end end
return clusterstore return clusterstore

View file

@ -1,5 +1,5 @@
local class = require "middleclass" local class = require "middleclass"
local datastore = class("datastore") local datastore = class("datastore")
function datastore:initialize() function datastore:initialize()
self.dict = ngx.shared.datastore self.dict = ngx.shared.datastore
@ -48,4 +48,4 @@ function datastore:delete_all(pattern)
return true, "success" return true, "success"
end end
return datastore return datastore

View file

@ -17,7 +17,7 @@ helpers.load_plugin = function(json)
end end
-- Check fields -- Check fields
local missing_fields = {} local missing_fields = {}
local required_fields = {"id", "order", "name", "description", "version", "settings"} local required_fields = { "id", "order", "name", "description", "version", "settings" }
for i, field in ipairs(required_fields) do for i, field in ipairs(required_fields) do
if plugin[field] == nil then if plugin[field] == nil then
valid_json = false valid_json = false
@ -72,7 +72,7 @@ helpers.call_plugin = function(plugin, method)
end end
-- Check values -- Check values
local missing_values = {} local missing_values = {}
local required_values = {"ret", "msg"} local required_values = { "ret", "msg" }
for i, value in ipairs(required_values) do for i, value in ipairs(required_values) do
if ret[value] == nil then if ret[value] == nil then
table.insert(missing_values, value) table.insert(missing_values, value)
@ -128,4 +128,4 @@ helpers.fill_ctx = function()
return true, "ctx filled", errors return true, "ctx filled", errors
end end
return helpers return helpers

View file

@ -1,13 +1,13 @@
local errlog = require "ngx.errlog" local errlog = require "ngx.errlog"
local class = require "middleclass" local class = require "middleclass"
local logger = class("logger") local logger = class("logger")
function logger:initialize(prefix) function logger:initialize(prefix)
self.prefix = string.upper(prefix) self.prefix = string.upper(prefix)
end end
function logger:log(level, msg) function logger:log(level, msg)
errlog.raw_log(level, "[" .. self.prefix .. "] " .. msg) errlog.raw_log(level, "[" .. self.prefix .. "] " .. msg)
end end
return logger return logger

View file

@ -2,7 +2,7 @@ local class = require "middleclass"
local logger = require "bunkerweb.logger" local logger = require "bunkerweb.logger"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cjson = require "cjson" local cjson = require "cjson"
local plugin = class("plugin") local plugin = class("plugin")
function plugin:initialize(id) function plugin:initialize(id)
@ -22,7 +22,7 @@ function plugin:initialize(id)
local metadata = cjson.decode(encoded_metadata) local metadata = cjson.decode(encoded_metadata)
local multisite = false local multisite = false
local current_phase = ngx.get_phase() local current_phase = ngx.get_phase()
for i, check_phase in ipairs({"set", "access", "log", "preread"}) do for i, check_phase in ipairs({ "set", "access", "log", "preread" }) do
if current_phase == check_phase then if current_phase == check_phase then
multisite = true multisite = true
break break
@ -54,7 +54,7 @@ function plugin:get_id()
end end
function plugin:ret(ret, msg, status, redirect) function plugin:ret(ret, msg, status, redirect)
return {ret = ret, msg = msg, status = status, redirect = redirect} return { ret = ret, msg = msg, status = status, redirect = redirect }
end end
return plugin return plugin

View file

@ -1,18 +1,18 @@
local cdatastore = require "bunkerweb.datastore" local cdatastore = require "bunkerweb.datastore"
local mmdb = require "bunkerweb.mmdb" local mmdb = require "bunkerweb.mmdb"
local clogger = require "bunkerweb.logger" local clogger = require "bunkerweb.logger"
local ipmatcher = require "resty.ipmatcher" local ipmatcher = require "resty.ipmatcher"
local resolver = require "resty.dns.resolver" local resolver = require "resty.dns.resolver"
local session = require "resty.session" local session = require "resty.session"
local cjson = require "cjson" local cjson = require "cjson"
local logger = clogger:new("UTILS") local logger = clogger:new("UTILS")
local datastore = cdatastore:new() local datastore = cdatastore:new()
local utils = {} local utils = {}
utils.get_variable = function(var, site_search) utils.get_variable = function(var, site_search)
-- Default site search to true -- Default site search to true
if site_search == nil then if site_search == nil then
site_search = true site_search = true
@ -40,7 +40,7 @@ utils.get_variable = function(var, site_search)
return value, "success" return value, "success"
end end
utils.has_variable = function(var, value) utils.has_variable = function(var, value)
-- Get global variable -- Get global variable
local check_value, err = datastore:get("variable_" .. var) local check_value, err = datastore:get("variable_" .. var)
if not value then if not value then
@ -71,7 +71,7 @@ utils.has_variable = function(var, value)
return check_value == value, "success" return check_value == value, "success"
end end
utils.has_not_variable = function(var, value) utils.has_not_variable = function(var, value)
-- Get global variable -- Get global variable
local check_value, err = datastore:get("variable_" .. var) local check_value, err = datastore:get("variable_" .. var)
if not value then if not value then
@ -132,7 +132,7 @@ utils.get_multiple_variables = function(vars)
return result return result
end end
utils.is_ip_in_networks = function(ip, networks) utils.is_ip_in_networks = function(ip, networks)
-- Instantiate ipmatcher -- Instantiate ipmatcher
local ipm, err = ipmatcher.new(networks) local ipm, err = ipmatcher.new(networks)
if not ipm then if not ipm then
@ -146,15 +146,15 @@ utils.is_ip_in_networks = function(ip, networks)
return matched return matched
end end
utils.is_ipv4 = function(ip) utils.is_ipv4 = function(ip)
return ipmatcher.parse_ipv4(ip) return ipmatcher.parse_ipv4(ip)
end end
utils.is_ipv6 = function(ip) utils.is_ipv6 = function(ip)
return ipmatcher.parse_ipv6(ip) return ipmatcher.parse_ipv6(ip)
end end
utils.ip_is_global = function(ip) utils.ip_is_global = function(ip)
-- Reserved, non public IPs -- Reserved, non public IPs
local reserved_ips = { local reserved_ips = {
"0.0.0.0/8", "0.0.0.0/8",
@ -201,7 +201,7 @@ utils.ip_is_global = function(ip)
return not matched, "success" return not matched, "success"
end end
utils.get_integration = function() utils.get_integration = function()
-- Check if already in datastore -- Check if already in datastore
local integration, err = datastore:get("misc_integration") local integration, err = datastore:get("misc_integration")
if integration then if integration then
@ -236,7 +236,7 @@ utils.get_integration = function()
if data:find("Alpine") then if data:find("Alpine") then
integration = "docker" integration = "docker"
end end
-- Strange case ... -- Strange case ...
else else
integration = "unknown" integration = "unknown"
end end
@ -252,7 +252,7 @@ utils.get_integration = function()
return integration return integration
end end
utils.get_version = function() utils.get_version = function()
-- Check if already in datastore -- Check if already in datastore
local version, err = datastore:get("misc_version") local version, err = datastore:get("misc_version")
if version then if version then
@ -274,7 +274,7 @@ utils.get_version = function()
return version return version
end end
utils.get_reason = function() utils.get_reason = function()
-- ngx.ctx -- ngx.ctx
if ngx.ctx.reason then if ngx.ctx.reason then
return ngx.ctx.reason return ngx.ctx.reason
@ -299,7 +299,7 @@ utils.get_reason = function()
return nil return nil
end end
utils.get_resolvers = function() utils.get_resolvers = function()
-- Get resolvers from datastore if existing -- Get resolvers from datastore if existing
local str_resolvers, err = datastore:get("misc_resolvers") local str_resolvers, err = datastore:get("misc_resolvers")
if str_resolvers then if str_resolvers then
@ -324,7 +324,7 @@ utils.get_resolvers = function()
return resolvers return resolvers
end end
utils.get_rdns = function(ip) utils.get_rdns = function(ip)
-- Check cache -- Check cache
local cachestore = utils.new_cachestore() local cachestore = utils.new_cachestore()
local ok, value = cachestore:get("rdns_" .. ip) local ok, value = cachestore:get("rdns_" .. ip)
@ -371,7 +371,7 @@ utils.get_rdns = function(ip)
return ptrs, ret_err return ptrs, ret_err
end end
utils.get_ips = function(fqdn, ipv6) utils.get_ips = function(fqdn, ipv6)
-- Check cache -- Check cache
local cachestore = utils.new_cachestore() local cachestore = utils.new_cachestore()
local ok, value = cachestore:get("dns_" .. fqdn) local ok, value = cachestore:get("dns_" .. fqdn)
@ -445,7 +445,7 @@ utils.get_ips = function(fqdn, ipv6)
return ips, cjson.encode(res_errors) .. " " .. cjson.encode(ans_errors) return ips, cjson.encode(res_errors) .. " " .. cjson.encode(ans_errors)
end end
utils.get_country = function(ip) utils.get_country = function(ip)
-- Check if mmdb is loaded -- Check if mmdb is loaded
if not mmdb.country_db then if not mmdb.country_db then
return false, "mmdb country not loaded" return false, "mmdb country not loaded"
@ -461,7 +461,7 @@ utils.get_country = function(ip)
return result.country.iso_code, "success" return result.country.iso_code, "success"
end end
utils.get_asn = function(ip) utils.get_asn = function(ip)
-- Check if mmdp is loaded -- Check if mmdp is loaded
if not mmdb.asn_db then if not mmdb.asn_db then
return false, "mmdb asn not loaded" return false, "mmdb asn not loaded"
@ -477,7 +477,7 @@ utils.get_asn = function(ip)
return result.autonomous_system_number, "success" return result.autonomous_system_number, "success"
end end
utils.rand = function(nb, no_numbers) utils.rand = function(nb, no_numbers)
local charset = {} local charset = {}
-- lowers, uppers and numbers -- lowers, uppers and numbers
if not no_numbers then if not no_numbers then
@ -492,7 +492,7 @@ utils.rand = function(nb, no_numbers)
return result return result
end end
utils.get_deny_status = function() utils.get_deny_status = function()
-- Stream case -- Stream case
if ngx.ctx.bw and ngx.ctx.bw.kind == "stream" then if ngx.ctx.bw and ngx.ctx.bw.kind == "stream" then
return 444 return 444
@ -506,14 +506,14 @@ utils.get_deny_status = function()
return tonumber(status) return tonumber(status)
end end
utils.get_session = function(audience) utils.get_session = function(audience)
-- Session already in context -- Session already in context
if ngx.ctx.bw.session then if ngx.ctx.bw.session then
ngx.ctx.bw.session:set_audience(audience) ngx.ctx.bw.session:set_audience(audience)
return ngx.ctx.bw.session return ngx.ctx.bw.session
end end
-- Open session and fill ctx -- Open session and fill ctx
local _session, err, exists, refreshed = session.start({audience = audience}) local _session, err, exists, refreshed = session.start({ audience = audience })
if err and err ~= "missing session cookie" and err ~= "no session" then if err and err ~= "missing session cookie" and err ~= "no session" then
logger:log(ngx.ERR, "session:start() error : " .. err) logger:log(ngx.ERR, "session:start() error : " .. err)
end end
@ -522,7 +522,7 @@ utils.get_session = function(audience)
return _session return _session
end end
utils.is_banned = function(ip) utils.is_banned = function(ip)
-- Check on local datastore -- Check on local datastore
local reason, err = datastore:get("bans_ip_" .. ip) local reason, err = datastore:get("bans_ip_" .. ip)
if not reason and err ~= "not found" then if not reason and err ~= "not found" then
@ -585,7 +585,7 @@ utils.is_banned = function(ip)
return false, "not banned" return false, "not banned"
end end
utils.add_ban = function(ip, reason, ttl) utils.add_ban = function(ip, reason, ttl)
-- Set on local datastore -- Set on local datastore
local ok, err = datastore:set("bans_ip_" .. ip, reason, ttl) local ok, err = datastore:set("bans_ip_" .. ip, reason, ttl)
if not ok then if not ok then
@ -614,7 +614,7 @@ utils.add_ban = function(ip, reason, ttl)
return true, "success" return true, "success"
end end
utils.new_cachestore = function() utils.new_cachestore = function()
-- Check if redis is used -- Check if redis is used
local use_redis, err = utils.get_variable("USE_REDIS", false) local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then if not use_redis then
@ -626,4 +626,4 @@ utils.new_cachestore = function()
return require "bunkerweb.cachestore":new(use_redis) return require "bunkerweb.cachestore":new(use_redis)
end end
return utils return utils

View file

@ -1,12 +1,12 @@
local middleclass = { local middleclass = {
_VERSION = 'middleclass v4.1.1', _VERSION = 'middleclass v4.1.1',
_DESCRIPTION = 'Object Orientation for Lua', _DESCRIPTION = 'Object Orientation for Lua',
_URL = 'https://github.com/kikito/middleclass', _URL = 'https://github.com/kikito/middleclass',
_LICENSE = [[ _LICENSE = [[
MIT LICENSE MIT LICENSE
Copyright (c) 2011 Enrique García Cota Copyright (c) 2011 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including "Software"), to deal in the Software without restriction, including
@ -14,10 +14,10 @@ local middleclass = {
distribute, sublicense, and/or sell copies of the Software, and to distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to permit persons to whom the Software is furnished to do so, subject to
the following conditions: the following conditions:
The above copyright notice and this permission notice shall be included The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software. in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@ -26,169 +26,179 @@ local middleclass = {
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]] ]]
}
local function _createIndexWrapper(aClass, f)
if f == nil then
return aClass.__instanceDict
elseif type(f) == "function" then
return function(self, name)
local value = aClass.__instanceDict[name]
if value ~= nil then
return value
else
return (f(self, name))
end
end
else -- if type(f) == "table" then
return function(self, name)
local value = aClass.__instanceDict[name]
if value ~= nil then
return value
else
return f[name]
end
end
end
end
local function _propagateInstanceMethod(aClass, name, f)
f = name == "__index" and _createIndexWrapper(aClass, f) or f
aClass.__instanceDict[name] = f
for subclass in pairs(aClass.subclasses) do
if rawget(subclass.__declaredMethods, name) == nil then
_propagateInstanceMethod(subclass, name, f)
end
end
end
local function _declareInstanceMethod(aClass, name, f)
aClass.__declaredMethods[name] = f
if f == nil and aClass.super then
f = aClass.super.__instanceDict[name]
end
_propagateInstanceMethod(aClass, name, f)
end
local function _tostring(self) return "class " .. self.name end
local function _call(self, ...) return self:new(...) end
local function _createClass(name, super)
local dict = {}
dict.__index = dict
local aClass = {
name = name,
super = super,
static = {},
__instanceDict = dict,
__declaredMethods = {},
subclasses = setmetatable({}, { __mode = 'k' })
} }
local function _createIndexWrapper(aClass, f) if super then
if f == nil then setmetatable(aClass.static, {
return aClass.__instanceDict __index = function(_, k)
elseif type(f) == "function" then local result = rawget(dict, k)
return function(self, name) if result == nil then
local value = aClass.__instanceDict[name] return super.static[k]
if value ~= nil then
return value
else
return (f(self, name))
end end
return result
end end
else -- if type(f) == "table" then })
return function(self, name) else
local value = aClass.__instanceDict[name] setmetatable(aClass.static, { __index = function(_, k) return rawget(dict, k) end })
if value ~= nil then
return value
else
return f[name]
end
end
end
end end
local function _propagateInstanceMethod(aClass, name, f) setmetatable(aClass, {
f = name == "__index" and _createIndexWrapper(aClass, f) or f __index = aClass.static,
aClass.__instanceDict[name] = f __tostring = _tostring,
__call = _call,
for subclass in pairs(aClass.subclasses) do __newindex = _declareInstanceMethod
if rawget(subclass.__declaredMethods, name) == nil then })
_propagateInstanceMethod(subclass, name, f)
end return aClass
end end
local function _includeMixin(aClass, mixin)
assert(type(mixin) == 'table', "mixin must be a table")
for name, method in pairs(mixin) do
if name ~= "included" and name ~= "static" then aClass[name] = method end
end end
local function _declareInstanceMethod(aClass, name, f) for name, method in pairs(mixin.static or {}) do
aClass.__declaredMethods[name] = f aClass.static[name] = method
if f == nil and aClass.super then
f = aClass.super.__instanceDict[name]
end
_propagateInstanceMethod(aClass, name, f)
end end
local function _tostring(self) return "class " .. self.name end if type(mixin.included) == "function" then mixin:included(aClass) end
local function _call(self, ...) return self:new(...) end return aClass
end
local function _createClass(name, super)
local dict = {} local DefaultMixin = {
dict.__index = dict __tostring = function(self) return "instance of " .. tostring(self.class) end,
local aClass = { name = name, super = super, static = {}, initialize = function(self, ...)
__instanceDict = dict, __declaredMethods = {}, end,
subclasses = setmetatable({}, {__mode='k'}) }
isInstanceOf = function(self, aClass)
if super then return type(aClass) == 'table'
setmetatable(aClass.static, { and type(self) == 'table'
__index = function(_,k) and (self.class == aClass
local result = rawget(dict,k) or type(self.class) == 'table'
if result == nil then and type(self.class.isSubclassOf) == 'function'
return super.static[k] and self.class:isSubclassOf(aClass))
end end,
return result
end static = {
}) allocate = function(self)
else assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end }) return setmetatable({ class = self }, self.__instanceDict)
end
setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
__call = _call, __newindex = _declareInstanceMethod })
return aClass
end
local function _includeMixin(aClass, mixin)
assert(type(mixin) == 'table', "mixin must be a table")
for name,method in pairs(mixin) do
if name ~= "included" and name ~= "static" then aClass[name] = method end
end
for name,method in pairs(mixin.static or {}) do
aClass.static[name] = method
end
if type(mixin.included)=="function" then mixin:included(aClass) end
return aClass
end
local DefaultMixin = {
__tostring = function(self) return "instance of " .. tostring(self.class) end,
initialize = function(self, ...) end,
isInstanceOf = function(self, aClass)
return type(aClass) == 'table'
and type(self) == 'table'
and (self.class == aClass
or type(self.class) == 'table'
and type(self.class.isSubclassOf) == 'function'
and self.class:isSubclassOf(aClass))
end, end,
static = { new = function(self, ...)
allocate = function(self) assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") local instance = self:allocate()
return setmetatable({ class = self }, self.__instanceDict) instance:initialize(...)
end, return instance
end,
new = function(self, ...)
assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'") subclass = function(self, name)
local instance = self:allocate() assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
instance:initialize(...) assert(type(name) == "string", "You must provide a name(string) for your class")
return instance
end, local subclass = _createClass(name, self)
subclass = function(self, name) for methodName, f in pairs(self.__instanceDict) do
assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") if not (methodName == "__index" and type(f) == "table") then
assert(type(name) == "string", "You must provide a name(string) for your class") _propagateInstanceMethod(subclass, methodName, f)
local subclass = _createClass(name, self)
for methodName, f in pairs(self.__instanceDict) do
if not (methodName == "__index" and type(f) == "table") then
_propagateInstanceMethod(subclass, methodName, f)
end
end end
subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
self.subclasses[subclass] = true
self:subclassed(subclass)
return subclass
end,
subclassed = function(self, other) end,
isSubclassOf = function(self, other)
return type(other) == 'table' and
type(self.super) == 'table' and
( self.super == other or self.super:isSubclassOf(other) )
end,
include = function(self, ...)
assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
return self
end end
} subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
self.subclasses[subclass] = true
self:subclassed(subclass)
return subclass
end,
subclassed = function(self, other)
end,
isSubclassOf = function(self, other)
return type(other) == 'table' and
type(self.super) == 'table' and
(self.super == other or self.super:isSubclassOf(other))
end,
include = function(self, ...)
assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
for _, mixin in ipairs({ ... }) do _includeMixin(self, mixin) end
return self
end
} }
}
function middleclass.class(name, super)
assert(type(name) == 'string', "A name (string) is needed for the new class") function middleclass.class(name, super)
return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin) assert(type(name) == 'string', "A name (string) is needed for the new class")
end return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
end
setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
return middleclass
return middleclass

View file

@ -1,5 +1,5 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local cjson = require "cjson" local cjson = require "cjson"
@ -8,12 +8,12 @@ local base64 = require "base64"
local sha256 = require "resty.sha256" local sha256 = require "resty.sha256"
local str = require "resty.string" local str = require "resty.string"
local http = require "resty.http" local http = require "resty.http"
local template = nil local template = nil
if ngx.shared.datastore then if ngx.shared.datastore then
template = require "resty.template" template = require "resty.template"
end end
local antibot = class("antibot", plugin) local antibot = class("antibot", plugin)
function antibot:initialize() function antibot:initialize()
-- Call parent initialize -- Call parent initialize
@ -173,7 +173,6 @@ function antibot:prepare_challenge()
end end
function antibot:display_challenge() function antibot:display_challenge()
-- Check if prepared -- Check if prepared
if not self.session_data.prepared then if not self.session_data.prepared then
return false, "challenge not prepared" return false, "challenge not prepared"
@ -274,7 +273,9 @@ function antibot:check_challenge()
end end
local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", { local res, err = httpc:request_uri("https://www.google.com/recaptcha/api/siteverify", {
method = "POST", method = "POST",
body = "secret=" .. self.variables["ANTIBOT_RECAPTCHA_SECRET"] .. "&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr, body = "secret=" ..
self.variables["ANTIBOT_RECAPTCHA_SECRET"] ..
"&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr,
headers = { headers = {
["Content-Type"] = "application/x-www-form-urlencoded" ["Content-Type"] = "application/x-www-form-urlencoded"
} }
@ -308,7 +309,9 @@ function antibot:check_challenge()
end end
local res, err = httpc:request_uri("https://hcaptcha.com/siteverify", { local res, err = httpc:request_uri("https://hcaptcha.com/siteverify", {
method = "POST", method = "POST",
body = "secret=" .. self.variables["ANTIBOT_HCAPTCHA_SECRET"] .. "&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr, body = "secret=" ..
self.variables["ANTIBOT_HCAPTCHA_SECRET"] ..
"&response=" .. args["token"] .. "&remoteip=" .. ngx.ctx.bw.remote_addr,
headers = { headers = {
["Content-Type"] = "application/x-www-form-urlencoded" ["Content-Type"] = "application/x-www-form-urlencoded"
} }

View file

@ -11,19 +11,18 @@ local mt = { __index = {} }
function _M.new() function _M.new()
local cap = {} local cap = {}
local f = setmetatable({ cap = cap}, mt) local f = setmetatable({ cap = cap }, mt)
return f return f
end end
local function urandom() local function urandom()
local seed = 1 local seed = 1
local devurandom = io.open("/dev/urandom", "r") local devurandom = io.open("/dev/urandom", "r")
local urandom = devurandom:read(32) local urandom = devurandom:read(32)
devurandom:close() devurandom:close()
for i=1,string.len(urandom) do for i = 1, string.len(urandom) do
local s = string.byte(urandom,i) local s = string.byte(urandom, i)
seed = seed + s seed = seed + s
end end
return seed return seed
@ -37,10 +36,10 @@ local function random_char(length)
local captcha_t = {} local captcha_t = {}
math.randomseed(urandom()) math.randomseed(urandom())
for c=1,length do for c = 1, length do
local i = math.random(1, string.len(set)) local i = math.random(1, string.len(set))
table.insert(captcha_t, string.sub(set,i,i)) table.insert(captcha_t, string.sub(set, i, i))
end end
return captcha_t return captcha_t
@ -49,11 +48,11 @@ end
local function random_angle() local function random_angle()
math.randomseed(urandom()) math.randomseed(urandom())
return math.random(-20, 40) return math.random(-20, 40)
end end
local function scribble(w,h) local function scribble(w, h)
math.randomseed(urandom()) math.randomseed(urandom())
local x1 = math.random(5, w - 5) local x1 = math.random(5, w - 5)
local x2 = math.random(5, w - 5) local x2 = math.random(5, w - 5)
@ -73,39 +72,36 @@ function mt.__index:length(l)
self.cap.length = l self.cap.length = l
end end
function mt.__index:bgcolor(r, g, b)
function mt.__index:bgcolor(r,g,b) self.cap.bgcolor = { r = r, g = g, b = b }
self.cap.bgcolor = { r = r , g = g , b = b}
end end
function mt.__index:fgcolor(r,g,b) function mt.__index:fgcolor(r, g, b)
self.cap.fgcolor = { r = r , g = g , b = b} self.cap.fgcolor = { r = r, g = g, b = b }
end end
function mt.__index:line(line) function mt.__index:line(line)
self.cap.line = line self.cap.line = line
end end
function mt.__index:font(font) function mt.__index:font(font)
self.cap.font = font self.cap.font = font
end end
function mt.__index:generate() function mt.__index:generate()
--local self.captcha = {} --local self.captcha = {}
local captcha_t = {} local captcha_t = {}
if not self.cap.string then if not self.cap.string then
if not self.cap.length then if not self.cap.length then
self.cap.length = 6 self.cap.length = 6
end end
captcha_t = random_char(self.cap.length) captcha_t = random_char(self.cap.length)
self:string(table.concat(captcha_t)) self:string(table.concat(captcha_t))
else else
for i=1, #self.cap.string do for i = 1, #self.cap.string do
table.insert(captcha_t, string.sub(self.cap.string, i, i)) table.insert(captcha_t, string.sub(self.cap.string, i, i))
end end
end end
@ -114,45 +110,45 @@ function mt.__index:generate()
local white = self.im:colorAllocate(255, 255, 255) local white = self.im:colorAllocate(255, 255, 255)
local bgcolor local bgcolor
if not self.cap.bgcolor then if not self.cap.bgcolor then
bgcolor = white bgcolor = white
else else
bgcolor = self.im:colorAllocate(self.cap.bgcolor.r , self.cap.bgcolor.g, self.cap.bgcolor.b ) bgcolor = self.im:colorAllocate(self.cap.bgcolor.r, self.cap.bgcolor.g, self.cap.bgcolor.b)
end end
local fgcolor local fgcolor
if not self.cap.fgcolor then if not self.cap.fgcolor then
fgcolor = black fgcolor = black
else else
fgcolor = self.im:colorAllocate(self.cap.fgcolor.r , self.cap.fgcolor.g, self.cap.fgcolor.b ) fgcolor = self.im:colorAllocate(self.cap.fgcolor.r, self.cap.fgcolor.g, self.cap.fgcolor.b)
end end
self.im:filledRectangle(0, 0, #captcha_t * 40, 45, bgcolor) self.im:filledRectangle(0, 0, #captcha_t * 40, 45, bgcolor)
local offset_left = 10 local offset_left = 10
for i=1, #captcha_t do for i = 1, #captcha_t do
local angle = random_angle() local angle = random_angle()
local llx, lly, lrx, lry, urx, ury, ulx, uly = self.im:stringFT(fgcolor, self.cap.font, 25, math.rad(angle), offset_left, 35, captcha_t[i]) local llx, lly, lrx, lry, urx, ury, ulx, uly = self.im:stringFT(fgcolor, self.cap.font, 25, math.rad(angle),
self.im:polygon({ {llx, lly}, {lrx, lry}, {urx, ury}, {ulx, uly} }, bgcolor) offset_left, 35, captcha_t[i])
self.im:polygon({ { llx, lly }, { lrx, lry }, { urx, ury }, { ulx, uly } }, bgcolor)
offset_left = offset_left + 40 offset_left = offset_left + 40
end end
if self.cap.line then if self.cap.line then
self.im:line(10, 10, ( #captcha_t * 40 ) - 10 , 40, fgcolor) self.im:line(10, 10, (#captcha_t * 40) - 10, 40, fgcolor)
self.im:line(11, 11, ( #captcha_t * 40 ) - 11 , 41, fgcolor) self.im:line(11, 11, (#captcha_t * 40) - 11, 41, fgcolor)
self.im:line(12, 12, ( #captcha_t * 40 ) - 12 , 42, fgcolor) self.im:line(12, 12, (#captcha_t * 40) - 12, 42, fgcolor)
end end
if self.cap.scribble then if self.cap.scribble then
for i=1,self.cap.scribble do for i = 1, self.cap.scribble do
local x1,x2 = scribble( #captcha_t * 40 , 45 ) local x1, x2 = scribble(#captcha_t * 40, 45)
self.im:line(x1, 5, x2, 40, fgcolor) self.im:line(x1, 5, x2, 40, fgcolor)
end end
end end
end end
-- Perhaps it's not the best solution -- Perhaps it's not the best solution
-- Writes the generated image to a jpeg file -- Writes the generated image to a jpeg file
function mt.__index:jpeg(outfile, quality) function mt.__index:jpeg(outfile, quality)
@ -189,4 +185,4 @@ function mt.__index:write(outfile, quality)
return self:getStr() return self:getStr()
end end
return _M return _M

View file

@ -1,6 +1,6 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local badbehavior = class("badbehavior", plugin) local badbehavior = class("badbehavior", plugin)
@ -34,7 +34,9 @@ function badbehavior:log()
return self:ret(true, "already banned") return self:ret(true, "already banned")
end end
-- Call increase function later and with cosocket enabled -- Call increase function later and with cosocket enabled
local ok, err = ngx.timer.at(0, badbehavior.increase, ngx.ctx.bw.remote_addr, tonumber(self.variables["BAD_BEHAVIOR_COUNT_TIME"]), tonumber(self.variables["BAD_BEHAVIOR_BAN_TIME"]), tonumber(self.variables["BAD_BEHAVIOR_THRESHOLD"]), self.use_redis) local ok, err = ngx.timer.at(0, badbehavior.increase, ngx.ctx.bw.remote_addr,
tonumber(self.variables["BAD_BEHAVIOR_COUNT_TIME"]), tonumber(self.variables["BAD_BEHAVIOR_BAN_TIME"]),
tonumber(self.variables["BAD_BEHAVIOR_THRESHOLD"]), self.use_redis)
if not ok then if not ok then
return self:ret(false, "can't create increase timer : " .. err) return self:ret(false, "can't create increase timer : " .. err)
end end
@ -93,9 +95,11 @@ function badbehavior.increase(premature, ip, count_time, ban_time, threshold, us
logger:log(ngx.ERR, "(increase) can't save ban : " .. err) logger:log(ngx.ERR, "(increase) can't save ban : " .. err)
return return
end end
logger:log(ngx.WARN, "IP " .. ip .. " is banned for " .. ban_time .. "s (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")") logger:log(ngx.WARN,
"IP " .. ip .. " is banned for " .. ban_time .. "s (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
end end
logger:log(ngx.NOTICE, "increased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")") logger:log(ngx.NOTICE,
"increased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
end end
function badbehavior.decrease(premature, ip, count_time, threshold, use_redis) function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
@ -136,7 +140,8 @@ function badbehavior.decrease(premature, ip, count_time, threshold, use_redis)
return return
end end
end end
logger:log(ngx.NOTICE, "decreased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")") logger:log(ngx.NOTICE,
"decreased counter for IP " .. ip .. " (" .. tostring(counter) .. "/" .. tostring(threshold) .. ")")
end end
function badbehavior.redis_increase(ip, count_time, ban_time) function badbehavior.redis_increase(ip, count_time, ban_time)
@ -169,7 +174,8 @@ function badbehavior.redis_increase(ip, count_time, ban_time)
return false, err return false, err
end end
-- Execute LUA script -- Execute LUA script
local counter, err = clusterstore:call("eval", redis_script, 2, "bad_behavior_" .. ip, "bans_ip" .. ip, count_time, ban_time) local counter, err = clusterstore:call("eval", redis_script, 2, "bad_behavior_" .. ip, "bans_ip" .. ip, count_time,
ban_time)
if not counter then if not counter then
clusterstore:close() clusterstore:close()
return false, err return false, err
@ -217,4 +223,4 @@ function badbehavior.redis_decrease(ip, count_time)
return counter return counter
end end
return badbehavior return badbehavior

View file

@ -1,12 +1,12 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson" local cjson = require "cjson"
local ipmatcher = require "resty.ipmatcher" local ipmatcher = require "resty.ipmatcher"
local blacklist = class("blacklist", plugin) local blacklist = class("blacklist", plugin)
function blacklist:initialize() function blacklist:initialize()
-- Call parent initialize -- Call parent initialize
@ -161,7 +161,6 @@ function blacklist:access()
-- Return -- Return
return self:ret(true, "not blacklisted") return self:ret(true, "not blacklisted")
end end
function blacklist:preread() function blacklist:preread()
@ -182,7 +181,7 @@ function blacklist:is_in_cache(ele)
local ok, data = self.cachestore:get("plugin_blacklist_" .. ngx.ctx.bw.server_name .. ele) local ok, data = self.cachestore:get("plugin_blacklist_" .. ngx.ctx.bw.server_name .. ele)
if not ok then if not ok then
return false, data return false, data
end end
return true, data return true, data
end end
@ -190,7 +189,7 @@ function blacklist:add_to_cache(ele, value)
local ok, err = self.cachestore:set("plugin_blacklist_" .. ngx.ctx.bw.server_name .. ele, value, 86400) local ok, err = self.cachestore:set("plugin_blacklist_" .. ngx.ctx.bw.server_name .. ele, value, 86400)
if not ok then if not ok then
return false, err return false, err
end end
return true return true
end end
@ -243,7 +242,7 @@ function blacklist:is_blacklisted_ip()
local ignore = false local ignore = false
for i, rdns in ipairs(rdns_list) do for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["IGNORE_RDNS"]) do for j, suffix in ipairs(self.lists["IGNORE_RDNS"]) do
if rdns:sub(-#suffix) == suffix then if rdns:sub(- #suffix) == suffix then
ignore = true ignore = true
break break
end end
@ -253,7 +252,7 @@ function blacklist:is_blacklisted_ip()
if not ignore then if not ignore then
for i, rdns in ipairs(rdns_list) do for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then if rdns:sub(- #suffix) == suffix then
return true, "rDNS " .. suffix return true, "rDNS " .. suffix
end end
end end
@ -333,4 +332,4 @@ function blacklist:is_blacklisted_ua()
return false, "ok" return false, "ok"
end end
return blacklist return blacklist

View file

@ -31,7 +31,7 @@ function cors:header()
local vary = ngx.header.Vary local vary = ngx.header.Vary
if vary then if vary then
if type(vary) == "string" then if type(vary) == "string" then
ngx.header.Vary = {vary, "Origin"} ngx.header.Vary = { vary, "Origin" }
else else
table.insert(vary, "Origin") table.insert(vary, "Origin")
ngx.header.Vary = vary ngx.header.Vary = vary

View file

@ -1,10 +1,10 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson" local cjson = require "cjson"
local country = class("country", plugin) local country = class("country", plugin)
function country:initialize() function country:initialize()
-- Call parent initialize -- Call parent initialize
@ -28,9 +28,13 @@ function country:access()
if data then if data then
data = cjson.decode(data) data = cjson.decode(data)
if data.result == "ok" then if data.result == "ok" then
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in country cache (not blacklisted, country = " .. data.country .. ")") return self:ret(true,
"client IP " ..
ngx.ctx.bw.remote_addr .. " is in country cache (not blacklisted, country = " .. data.country .. ")")
end end
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in country cache (blacklisted, country = " .. data.country .. ")", utils.get_deny_status()) return self:ret(true,
"client IP " .. ngx.ctx.bw.remote_addr .. " is in country cache (blacklisted, country = " .. data.country .. ")",
utils.get_deny_status())
end end
-- Don't go further if IP is not global -- Don't go further if IP is not global
@ -47,7 +51,7 @@ function country:access()
if not country then if not country then
return self:ret(false, "can't get country of client IP " .. ngx.ctx.bw.remote_addr .. " : " .. err) return self:ret(false, "can't get country of client IP " .. ngx.ctx.bw.remote_addr .. " : " .. err)
end end
-- Process whitelist first -- Process whitelist first
if self.variables["WHITELIST_COUNTRY"] ~= "" then if self.variables["WHITELIST_COUNTRY"] ~= "" then
for wh_country in self.variables["WHITELIST_COUNTRY"]:gmatch("%S+") do for wh_country in self.variables["WHITELIST_COUNTRY"]:gmatch("%S+") do
@ -63,9 +67,10 @@ function country:access()
if not ok then if not ok then
return self:ret(false, "error while adding item to cache : " .. err) return self:ret(false, "error while adding item to cache : " .. err)
end end
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is not whitelisted (country = " .. country .. ")", utils.get_deny_status()) return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is not whitelisted (country = " .. country .. ")",
utils.get_deny_status())
end end
-- And then blacklist -- And then blacklist
if self.variables["BLACKLIST_COUNTRY"] ~= "" then if self.variables["BLACKLIST_COUNTRY"] ~= "" then
for bl_country in self.variables["BLACKLIST_COUNTRY"]:gmatch("%S+") do for bl_country in self.variables["BLACKLIST_COUNTRY"]:gmatch("%S+") do
@ -74,7 +79,8 @@ function country:access()
if not ok then if not ok then
return self:ret(false, "error while adding item to cache : " .. err) return self:ret(false, "error while adding item to cache : " .. err)
end end
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is blacklisted (country = " .. country .. ")", utils.get_deny_status()) return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is blacklisted (country = " .. country .. ")",
utils.get_deny_status())
end end
end end
end end
@ -95,16 +101,17 @@ function country:is_in_cache(ip)
local ok, data = self.cachestore:get("plugin_country_cache_" .. ngx.ctx.bw.server_name .. ip) local ok, data = self.cachestore:get("plugin_country_cache_" .. ngx.ctx.bw.server_name .. ip)
if not ok then if not ok then
return false, data return false, data
end end
return true, data return true, data
end end
function country:add_to_cache(ip, country, result) function country:add_to_cache(ip, country, result)
local ok, err = self.cachestore:set("plugin_country_cache_" .. ngx.ctx.bw.server_name .. ip, cjson.encode({country = country, result = result}), 86400) local ok, err = self.cachestore:set("plugin_country_cache_" .. ngx.ctx.bw.server_name .. ip,
cjson.encode({ country = country, result = result }), 86400)
if not ok then if not ok then
return false, err return false, err
end end
return true return true
end end
return country return country

View file

@ -1,11 +1,11 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson" local cjson = require "cjson"
local resolver = require "resty.dns.resolver" local resolver = require "resty.dns.resolver"
local dnsbl = class("dnsbl", plugin) local dnsbl = class("dnsbl", plugin)
function dnsbl:initialize() function dnsbl:initialize()
-- Call parent initialize -- Call parent initialize
@ -65,7 +65,8 @@ function dnsbl:access()
if cached == "ok" then if cached == "ok" then
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in DNSBL cache (not blacklisted)") return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in DNSBL cache (not blacklisted)")
end end
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in DNSBL cache (server = " .. cached .. ")", utils.get_deny_status()) return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is in DNSBL cache (server = " .. cached .. ")",
utils.get_deny_status())
end end
-- Loop on DNSBL list -- Loop on DNSBL list
for server in self.variables["DNSBL_LIST"]:gmatch("%S+") do for server in self.variables["DNSBL_LIST"]:gmatch("%S+") do
@ -105,7 +106,7 @@ function dnsbl:add_to_cache(ip, value)
local ok, err = self.cachestore:set("plugin_dnsbl_" .. ngx.ctx.bw.server_name .. ip, value, 86400) local ok, err = self.cachestore:set("plugin_dnsbl_" .. ngx.ctx.bw.server_name .. ip, value, 86400)
if not ok then if not ok then
return false, err return false, err
end end
return true return true
end end
@ -123,4 +124,4 @@ function dnsbl:is_in_dnsbl(ip, server)
return false, "success" return false, "success"
end end
return dnsbl return dnsbl

View file

@ -1,13 +1,13 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cjson = require "cjson" local cjson = require "cjson"
local template = nil local template = nil
if ngx.shared.datastore then if ngx.shared.datastore then
template = require "resty.template" template = require "resty.template"
end end
local errors = class("errors", plugin) local errors = class("errors", plugin)
function errors:initialize() function errors:initialize()
-- Call parent initialize -- Call parent initialize
@ -75,4 +75,4 @@ function errors:render_template(code)
}) })
end end
return errors return errors

View file

@ -1,11 +1,11 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson" local cjson = require "cjson"
local ipmatcher = require "resty.ipmatcher" local ipmatcher = require "resty.ipmatcher"
local greylist = class("greylist", plugin) local greylist = class("greylist", plugin)
function greylist:initialize() function greylist:initialize()
-- Call parent initialize -- Call parent initialize
@ -202,7 +202,7 @@ function greylist:is_greylisted_ip()
if rdns_list then if rdns_list then
for i, rdns in ipairs(rdns_list) do for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then if rdns:sub(- #suffix) == suffix then
return true, "rDNS " .. suffix return true, "rDNS " .. suffix
end end
end end
@ -216,7 +216,7 @@ function greylist:is_greylisted_ip()
if ngx.ctx.bw.ip_is_global then if ngx.ctx.bw.ip_is_global then
local asn, err = utils.get_asn(ngx.ctx.bw.remote_addr) local asn, err = utils.get_asn(ngx.ctx.bw.remote_addr)
if not asn then if not asn then
return nil, "ASN " .. err return nil, "ASN " .. err
end end
for i, bl_asn in ipairs(self.lists["ASN"]) do for i, bl_asn in ipairs(self.lists["ASN"]) do
if bl_asn == tostring(asn) then if bl_asn == tostring(asn) then
@ -255,7 +255,7 @@ function greylist:is_in_cache(ele)
local ok, data = self.cachestore:get("plugin_greylist_" .. ngx.ctx.bw.server_name .. ele) local ok, data = self.cachestore:get("plugin_greylist_" .. ngx.ctx.bw.server_name .. ele)
if not ok then if not ok then
return false, data return false, data
end end
return true, data return true, data
end end
@ -263,8 +263,8 @@ function greylist:add_to_cache(ele, value)
local ok, err = self.cachestore:set("plugin_greylist_" .. ngx.ctx.bw.server_name .. ele, value, 86400) local ok, err = self.cachestore:set("plugin_greylist_" .. ngx.ctx.bw.server_name .. ele, value, 86400)
if not ok then if not ok then
return false, err return false, err
end end
return true return true
end end
return greylist return greylist

View file

@ -1,7 +1,7 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cjson = require "cjson" local cjson = require "cjson"
local letsencrypt = class("letsencrypt", plugin) local letsencrypt = class("letsencrypt", plugin)
@ -48,4 +48,4 @@ function letsencrypt:api()
return true, ngx.HTTP_NOT_FOUND, { status = "error", msg = "unknown request" } return true, ngx.HTTP_NOT_FOUND, { status = "error", msg = "unknown request" }
end end
return letsencrypt return letsencrypt

View file

@ -1,11 +1,11 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local clusterstore = require "bunkerweb.clusterstore" local clusterstore = require "bunkerweb.clusterstore"
local cjson = require "cjson" local cjson = require "cjson"
local limit = class("limit", plugin) local limit = class("limit", plugin)
function limit:initialize() function limit:initialize()
-- Call parent initialize -- Call parent initialize
@ -66,7 +66,7 @@ function limit:init()
return self:ret(true, "no service uses limit for requests, skipping init") return self:ret(true, "no service uses limit for requests, skipping init")
end end
-- Get variables -- Get variables
local variables, err = utils.get_multiple_variables({"LIMIT_REQ_URL", "LIMIT_REQ_RATE"}) local variables, err = utils.get_multiple_variables({ "LIMIT_REQ_URL", "LIMIT_REQ_RATE" })
if variables == nil then if variables == nil then
return self:ret(false, err) return self:ret(false, err)
end end
@ -128,10 +128,19 @@ function limit:access()
end end
-- Limit reached -- Limit reached
if limited then if limited then
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is limited for URL " .. ngx.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")", ngx.HTTP_TOO_MANY_REQUESTS) return self:ret(true,
"client IP " ..
ngx.ctx.bw.remote_addr ..
" is limited for URL " ..
ngx.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")",
ngx.HTTP_TOO_MANY_REQUESTS)
end end
-- Limit not reached -- Limit not reached
return self:ret(true, "client IP " .. ngx.ctx.bw.remote_addr .. " is not limited for URL " .. ngx.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")") return self:ret(true,
"client IP " ..
ngx.ctx.bw.remote_addr ..
" is not limited for URL " ..
ngx.ctx.bw.uri .. " (current rate = " .. current_rate .. "r/" .. rate_time .. " and max rate = " .. rate .. ")")
end end
function limit:limit_req(rate_max, rate_time) function limit:limit_req(rate_max, rate_time)
@ -144,7 +153,9 @@ function limit:limit_req(rate_max, rate_time)
else else
timestamps = redis_timestamps timestamps = redis_timestamps
-- Save the new timestamps -- Save the new timestamps
local ok, err = self.datastore:set("plugin_limit_cache_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri, cjson.encode(timestamps), delay) local ok, err = self.datastore:set(
"plugin_limit_cache_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri,
cjson.encode(timestamps), delay)
if not ok then if not ok then
return nil, "can't update timestamps : " .. err return nil, "can't update timestamps : " .. err
end end
@ -166,7 +177,8 @@ end
function limit:limit_req_local(rate_max, rate_time) function limit:limit_req_local(rate_max, rate_time)
-- Get timestamps -- Get timestamps
local timestamps, err = self.datastore:get("plugin_limit_cache_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri) local timestamps, err = self.datastore:get("plugin_limit_cache_" ..
ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri)
if not timestamps and err ~= "not found" then if not timestamps and err ~= "not found" then
return nil, err return nil, err
elseif err == "not found" then elseif err == "not found" then
@ -177,7 +189,9 @@ function limit:limit_req_local(rate_max, rate_time)
local updated, new_timestamps, delay = self:limit_req_timestamps(rate_max, rate_time, timestamps) local updated, new_timestamps, delay = self:limit_req_timestamps(rate_max, rate_time, timestamps)
-- Save new timestamps if needed -- Save new timestamps if needed
if updated then if updated then
local ok, err = self.datastore:set("plugin_limit_cache_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri, cjson.encode(new_timestamps), delay) local ok, err = self.datastore:set(
"plugin_limit_cache_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri,
cjson.encode(new_timestamps), delay)
if not ok then if not ok then
return nil, err return nil, err
end end
@ -241,7 +255,9 @@ function limit:limit_req_redis(rate_max, rate_time)
return nil, err return nil, err
end end
-- Execute script -- Execute script
local timestamps, err = self.clusterstore:call("eval", redis_script, 1, "limit_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri, rate_max, rate_time, os.time(os.date("!*t"))) local timestamps, err = self.clusterstore:call("eval", redis_script, 1,
"limit_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri, rate_max, rate_time,
os.time(os.date("!*t")))
if not timestamps then if not timestamps then
self.clusterstore:close() self.clusterstore:close()
return nil, err return nil, err
@ -282,4 +298,4 @@ function limit:limit_req_timestamps(rate_max, rate_time, timestamps)
return updated, new_timestamps, delay return updated, new_timestamps, delay
end end
return limit return limit

View file

@ -1,10 +1,10 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local logger = require "bunkerweb.logger" local logger = require "bunkerweb.logger"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local clusterstore = require "bunkerweb.clusterstore" local clusterstore = require "bunkerweb.clusterstore"
local redis = class("redis", plugin) local redis = class("redis", plugin)
function redis:initialize() function redis:initialize()
-- Call parent initialize -- Call parent initialize
@ -34,4 +34,4 @@ function redis:init_worker()
return self:ret(true, "success") return self:ret(true, "success")
end end
return redis return redis

View file

@ -1,20 +1,20 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local reversescan = class("reversescan", plugin) local reversescan = class("reversescan", plugin)
function reversescan:initialize() function reversescan:initialize()
-- Call parent initialize -- Call parent initialize
plugin.initialize(self, "reversescan") plugin.initialize(self, "reversescan")
-- Instantiate cachestore -- Instantiate cachestore
local use_redis, err = utils.get_variable("USE_REDIS", false) local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then if not use_redis then
self.logger:log(ngx.ERR, err) self.logger:log(ngx.ERR, err)
end end
self.use_redis = use_redis == "yes" self.use_redis = use_redis == "yes"
self.cachestore = cachestore:new(self.use_redis) self.cachestore = cachestore:new(self.use_redis)
end end
function reversescan:access() function reversescan:access()
@ -30,10 +30,12 @@ function reversescan:access()
return self:ret(false, "error getting cache from datastore : " .. cached) return self:ret(false, "error getting cache from datastore : " .. cached)
end end
if cached == "open" then if cached == "open" then
return self:ret(true, "port " .. port .. " is opened for IP " .. ngx.ctx.bw.remote_addr, utils.get_deny_status()) return self:ret(true, "port " .. port .. " is opened for IP " .. ngx.ctx.bw.remote_addr,
utils.get_deny_status())
elseif not cached then elseif not cached then
-- Do the scan -- Do the scan
local res, err = self:scan(ngx.ctx.bw.remote_addr, tonumber(port), tonumber(self.variables["REVERSE_SCAN_TIMEOUT"])) local res, err = self:scan(ngx.ctx.bw.remote_addr, tonumber(port),
tonumber(self.variables["REVERSE_SCAN_TIMEOUT"]))
-- Cache the result -- Cache the result
local ok, err = self:add_to_cache(ngx.ctx.bw.remote_addr .. ":" .. port, res) local ok, err = self:add_to_cache(ngx.ctx.bw.remote_addr .. ":" .. port, res)
if not ok then if not ok then
@ -41,7 +43,8 @@ function reversescan:access()
end end
-- Deny request if port is open -- Deny request if port is open
if res == "open" then if res == "open" then
return self:ret(true, "port " .. port .. " is opened for IP " .. ngx.ctx.bw.remote_addr, utils.get_deny_status()) return self:ret(true, "port " .. port .. " is opened for IP " .. ngx.ctx.bw.remote_addr,
utils.get_deny_status())
end end
end end
end end
@ -50,7 +53,7 @@ function reversescan:access()
end end
function reversescan:preread() function reversescan:preread()
return self:access() return self:access()
end end
function reversescan:scan(ip, port, timeout) function reversescan:scan(ip, port, timeout)
@ -65,19 +68,19 @@ function reversescan:scan(ip, port, timeout)
end end
function reversescan:is_in_cache(ip_port) function reversescan:is_in_cache(ip_port)
local ok, data = self.cachestore:get("plugin_reversescan_cache_" .. ip_port) local ok, data = self.cachestore:get("plugin_reversescan_cache_" .. ip_port)
if not ok then if not ok then
return false, data return false, data
end end
return true, data return true, data
end end
function reversescan:add_to_cache(ip_port, value) function reversescan:add_to_cache(ip_port, value)
local ok, err = self.cachestore:set("plugin_reversescan_cache_" .. ip_port, value, 86400) local ok, err = self.cachestore:set("plugin_reversescan_cache_" .. ip_port, value, 86400)
if not ok then if not ok then
return false, err return false, err
end end
return true return true
end end
return reversescan return reversescan

View file

@ -1,7 +1,7 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local session = require "resty.session" local session = require "resty.session"
local sessions = class("sessions", plugin) local sessions = class("sessions", plugin)
@ -68,4 +68,4 @@ function sessions:init()
return self:ret(true, "sessions init successful") return self:ret(true, "sessions init successful")
end end
return sessions return sessions

View file

@ -1,17 +1,17 @@
local class = require "middleclass" local class = require "middleclass"
local plugin = require "bunkerweb.plugin" local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils" local utils = require "bunkerweb.utils"
local datastore = require "bunkerweb.datastore" local datastore = require "bunkerweb.datastore"
local cachestore = require "bunkerweb.cachestore" local cachestore = require "bunkerweb.cachestore"
local cjson = require "cjson" local cjson = require "cjson"
local ipmatcher = require "resty.ipmatcher" local ipmatcher = require "resty.ipmatcher"
local env = require "resty.env" local env = require "resty.env"
local whitelist = class("whitelist", plugin) local whitelist = class("whitelist", plugin)
function whitelist:initialize() function whitelist:initialize()
-- Call parent initialize -- Call parent initialize
plugin.initialize(self, "whitelist") plugin.initialize(self, "whitelist")
-- Check if redis is enabled -- Check if redis is enabled
local use_redis, err = utils.get_variable("USE_REDIS", false) local use_redis, err = utils.get_variable("USE_REDIS", false)
if not use_redis then if not use_redis then
@ -209,7 +209,7 @@ function whitelist:is_in_cache(ele)
local ok, data = self.cachestore:get("plugin_whitelist_" .. ngx.ctx.bw.server_name .. ele) local ok, data = self.cachestore:get("plugin_whitelist_" .. ngx.ctx.bw.server_name .. ele)
if not ok then if not ok then
return false, data return false, data
end end
return true, data return true, data
end end
@ -258,7 +258,7 @@ function whitelist:is_whitelisted_ip()
if rdns_list then if rdns_list then
for i, rdns in ipairs(rdns_list) do for i, rdns in ipairs(rdns_list) do
for j, suffix in ipairs(self.lists["RDNS"]) do for j, suffix in ipairs(self.lists["RDNS"]) do
if rdns:sub(-#suffix) == suffix then if rdns:sub(- #suffix) == suffix then
return true, "rDNS " .. suffix return true, "rDNS " .. suffix
end end
end end
@ -272,7 +272,7 @@ function whitelist:is_whitelisted_ip()
if ngx.ctx.bw.ip_is_global then if ngx.ctx.bw.ip_is_global then
local asn, err = utils.get_asn(ngx.ctx.bw.remote_addr) local asn, err = utils.get_asn(ngx.ctx.bw.remote_addr)
if not asn then if not asn then
return nil, "ASN " .. err return nil, "ASN " .. err
end end
for i, bl_asn in ipairs(self.lists["ASN"]) do for i, bl_asn in ipairs(self.lists["ASN"]) do
if bl_asn == tostring(asn) then if bl_asn == tostring(asn) then
@ -307,4 +307,4 @@ function whitelist:is_whitelisted_ua()
return false, "ok" return false, "ok"
end end
return whitelist return whitelist