Merge branch 'dev' of github.com:bunkerity/bunkerweb into dev

This commit is contained in:
florian 2023-05-20 17:46:49 +02:00
commit b19ebbe6a8
No known key found for this signature in database
GPG key ID: 3D80806F12602A7C
29 changed files with 788 additions and 103 deletions

View file

@ -1,5 +1,5 @@
mkdocs==1.4.3
mkdocs-material==9.1.12
mkdocs-material==9.1.13
pytablewriter==0.64.2
mike==1.1.2
jinja2<3.1.0

View file

@ -174,7 +174,8 @@ function badbehavior.redis_increase(ip, count_time, ban_time)
return false, err
end
-- Execute LUA script
local counter, err = clusterstore:call("eval", redis_script, 2, "bad_behavior_" .. ip, "bans_ip" .. ip, count_time,
local counter, err = clusterstore:call("eval", redis_script, 2, "plugin_bad_behavior_" .. ip, "bans_ip" .. ip,
count_time,
ban_time)
if not counter then
clusterstore:close()
@ -214,7 +215,7 @@ function badbehavior.redis_decrease(ip, count_time)
if not ok then
return false, err
end
local counter, err = clusterstore:call("eval", redis_script, 1, "bad_behavior_" .. ip, count_time)
local counter, err = clusterstore:call("eval", redis_script, 1, "plugin_bad_behavior_" .. ip, count_time)
if not counter then
clusterstore:close()
return false, err

View file

@ -98,7 +98,7 @@ function country:preread()
end
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_" .. ngx.ctx.bw.server_name .. ip)
if not ok then
return false, data
end
@ -106,7 +106,7 @@ function country:is_in_cache(ip)
end
function country:add_to_cache(ip, country, result)
local ok, err = self.cachestore:set("plugin_country_cache_" .. ngx.ctx.bw.server_name .. ip,
local ok, err = self.cachestore:set("plugin_country_" .. ngx.ctx.bw.server_name .. ip,
cjson.encode({ country = country, result = result }), 86400)
if not ok then
return false, err

View file

@ -39,7 +39,7 @@
"help": "Cookie flags automatically added to all cookies (value accepted for nginx_cookie_flag_module).",
"id": "cookie-flags",
"label": "Cookie flags",
"regex": "^(\\*|\\w+)( (HttpOnly|(SameSite)(?!.*\\4)(=(Lax|Strict))?)(?!.*\\3))*$",
"regex": "^(\\*|[^;]+)( (HttpOnly|(SameSite)(?!.*\\4)(=(Lax|Strict))?)(?!.*\\3))*$",
"type": "text",
"multiple": "cookie-flags"
},

View file

@ -154,7 +154,7 @@ function limit:limit_req(rate_max, rate_time)
timestamps = redis_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,
"plugin_limit_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri,
cjson.encode(timestamps), delay)
if not ok then
return nil, "can't update timestamps : " .. err
@ -177,8 +177,8 @@ end
function limit:limit_req_local(rate_max, rate_time)
-- 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_" ..
ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri)
if not timestamps and err ~= "not found" then
return nil, err
elseif err == "not found" then
@ -190,7 +190,7 @@ function limit:limit_req_local(rate_max, rate_time)
-- Save new timestamps if needed
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,
"plugin_limit_" .. ngx.ctx.bw.server_name .. ngx.ctx.bw.remote_addr .. ngx.ctx.bw.uri,
cjson.encode(new_timestamps), delay)
if not ok then
return nil, err
@ -256,7 +256,7 @@ function limit:limit_req_redis(rate_max, rate_time)
end
-- 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,
"plugin_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
self.clusterstore:close()

View file

@ -34,7 +34,7 @@ function reversescan:access()
utils.get_deny_status())
elseif not cached then
-- Do the scan
local res, err = self:scan(ngx.ctx.bw.remote_addr, tonumber(port),
local res = self:scan(ngx.ctx.bw.remote_addr, tonumber(port),
tonumber(self.variables["REVERSE_SCAN_TIMEOUT"]))
-- Cache the result
local ok, err = self:add_to_cache(ngx.ctx.bw.remote_addr .. ":" .. port, res)
@ -62,13 +62,13 @@ function reversescan:scan(ip, port, timeout)
local ok, err = tcpsock:connect(ip, port)
tcpsock:close()
if not ok then
return "close", err
return "close"
end
return "open", nil
return "open"
end
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_reverse_scan_" .. ip_port)
if not ok then
return false, data
end
@ -76,7 +76,7 @@ function reversescan:is_in_cache(ip_port)
end
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_reverse_scan_" .. ip_port, value, 86400)
if not ok then
return false, err
end

View file

@ -181,7 +181,7 @@ class Database:
try:
metadata = session.query(Metadata).get(1)
if metadata is None:
if not metadata:
return "The metadata are not set yet, try again"
metadata.autoconf_loaded = value
@ -435,11 +435,11 @@ class Database:
.first()
)
if service_setting is None:
if not service_setting:
if key != "SERVER_NAME" and (
value == setting.default
or (not value.strip() and setting.default is None)
(key not in config and value == setting.default)
or (key in config and value == config[key])
or (not value.strip() and not setting.default)
):
continue
@ -456,10 +456,10 @@ class Database:
method in (service_setting.method, "autoconf")
and service_setting.value != value
):
if (
value == setting.default
or (not value.strip() and setting.default is None)
if key != "SERVER_NAME" and (
(key not in config and value == setting.default)
or (key in config and value == config[key])
or (not value.strip() and not setting.default)
):
session.query(Services_settings).filter(
Services_settings.service_id == server_name,
@ -492,9 +492,9 @@ class Database:
.first()
)
if global_value is None:
if not global_value:
if value == setting.default or (
not value.strip() and setting.default is None
not value.strip() and not setting.default
):
continue
@ -511,7 +511,7 @@ class Database:
and global_value.value != value
):
if value == setting.default or (
not value.strip() and setting.default is None
not value.strip() and not setting.default
):
session.query(Global_values).filter(
Global_values.setting_id == key,
@ -570,9 +570,9 @@ class Database:
.first()
)
if global_value is None:
if not global_value:
if value == setting.default or (
not value.strip() and setting.default is None
not value.strip() and not setting.default
):
continue
@ -589,7 +589,7 @@ class Database:
and value != global_value.value
):
if value == setting.default or (
not value.strip() and setting.default is None
not value.strip() and not setting.default
):
session.query(Global_values).filter(
Global_values.setting_id == key,
@ -676,7 +676,7 @@ class Database:
.first()
)
if custom_conf is None:
if not custom_conf:
to_put.append(Custom_configs(**config))
elif config["checksum"] != custom_conf.checksum and method in (
custom_conf.method,
@ -870,7 +870,7 @@ class Database:
.first()
)
if job is None:
if not job:
return "Job not found"
job.last_run = datetime.now()
@ -908,7 +908,7 @@ class Database:
.first()
)
if cache is None:
if not cache:
session.add(
Jobs_cache(
job_name=job_name,
@ -1052,7 +1052,7 @@ class Database:
.first()
)
if setting not in db_ids or db_setting is None:
if setting not in db_ids or not db_setting:
for select in value.pop("select", []):
to_put.append(
Selects(setting_id=value["id"], value=select)
@ -1147,7 +1147,7 @@ class Database:
.first()
)
if job["name"] not in db_names or db_job is None:
if job["name"] not in db_names or not db_job:
job["file_name"] = job.pop("file")
job["reload"] = job.get("reload", False)
to_put.append(
@ -1197,7 +1197,7 @@ class Database:
.first()
)
if db_plugin_page is None:
if not db_plugin_page:
template = Path(f"{path_ui}/template.html").read_bytes()
actions = Path(f"{path_ui}/actions.py").read_bytes()
@ -1314,7 +1314,7 @@ class Database:
.first()
)
if db_plugin_page is None:
if not db_plugin_page:
template = Path(f"{path_ui}/template.html").read_bytes()
actions = Path(f"{path_ui}/actions.py").read_bytes()
@ -1634,7 +1634,7 @@ class Database:
.first()
)
if page is None:
if not page:
return None
return page.actions_file
@ -1649,7 +1649,7 @@ class Database:
.first()
)
if page is None:
if not page:
return None
return page.template_file

View file

@ -1,4 +1,4 @@
sqlalchemy==2.0.13
sqlalchemy==2.0.14
psycopg2-binary==2.9.6
PyMySQL==1.0.3
cryptography==40.0.2

View file

@ -225,48 +225,48 @@ pymysql==1.0.3 \
--hash=sha256:3dda943ef3694068a75d69d071755dbecacee1adf9a1fc5b206830d2b67d25e8 \
--hash=sha256:89fc6ae41c0aeb6e1f7710cdd623702ea2c54d040565767a78b00a5ebb12f4e5
# via -r requirements.in
sqlalchemy==2.0.13 \
--hash=sha256:0aa2cbde85a6eab9263ab480f19e8882d022d30ebcdc14d69e6a8d7c07b0a871 \
--hash=sha256:0d6979c9707f8b82366ba34b38b5a6fe32f75766b2e901f9820e271e95384070 \
--hash=sha256:0eb14a386a5b610305bec6639b35540b47f408b0a59f75999199aed5b3d40079 \
--hash=sha256:2424a84f131901fbb20a99844d47b38b517174c6e964c8efb15ea6bb9ced8c2b \
--hash=sha256:2ad9688debf1f0ae9c6e0706a4e2d33b1a01281317cee9bd1d7eef8020c5baac \
--hash=sha256:2f0a355264af0952570f18457102984e1f79510f856e5e0ae652e63316d1ca23 \
--hash=sha256:31f72bb300eed7bfdb373c7c046121d84fa0ae6f383089db9505ff553ac27cef \
--hash=sha256:375b7ba88f261dbd79d044f20cbcd919d88befb63f26af9d084614f10cdf97a6 \
--hash=sha256:37de4010f53f452e94e5ed6684480432cfe6a7a8914307ef819cd028b05b98d5 \
--hash=sha256:49c138856035cb97f0053e5e57ba90ec936b28a0b8b0020d44965c7b0c0bf03a \
--hash=sha256:4f9832815257969b3ca9bf0501351e4c02c8d60cbd3ec9f9070d5b0f8852900e \
--hash=sha256:566a0ac347cf4632f551e7b28bbd0d215af82e6ffaa2556f565a3b6b51dc3f81 \
--hash=sha256:6777673d346071451bf7cccf8d0499024f1bd6a835fc90b4fe7af50373d92ce6 \
--hash=sha256:72746ec17a7d9c5acf2c57a6e6190ceba3dad7127cd85bb17f24e90acc0e8e3f \
--hash=sha256:755f653d693f9b8f4286d987aec0d4279821bf8d179a9de8e8a5c685e77e57d6 \
--hash=sha256:7612a7366a0855a04430363fb4ab392dc6818aaece0b2e325ff30ee77af9b21f \
--hash=sha256:7ad24c85f2a1caf0cd1ae8c2fdb668777a51a02246d9039420f94bd7dbfd37ed \
--hash=sha256:881cc388dded44ae6e17a1666364b98bd76bcdc71b869014ae725f06ba298e0e \
--hash=sha256:8d97b37b4e60073c38bcf94e289e3be09ef9be870de88d163f16e08f2b9ded1a \
--hash=sha256:9119795d2405eb23bf7e6707e228fe38124df029494c1b3576459aa3202ea432 \
--hash=sha256:9136d596111c742d061c0f99bab95c5370016c4101a32e72c2b634ad5e0757e6 \
--hash=sha256:9ad883ac4f5225999747f0849643c4d0ec809d9ffe0ddc81a81dd3e68d0af463 \
--hash=sha256:a25b4c4fdd633501233924f873e6f6cd8970732859ecfe4ecfb60635881f70be \
--hash=sha256:a30e4db983faa5145e00ef6eaf894a2d503b3221dbf40a595f3011930d3d0bac \
--hash=sha256:a5e9e78332a5d841422b88b8c490dfd7f761e64b3430249b66c05d02f72ceab0 \
--hash=sha256:b4e08e3831671008888bad5d160d757ef35ce34dbb73b78c3998d16aa1334c97 \
--hash=sha256:bf1aae95e80acea02a0a622e1c12d3fefc52ffd0fe7bda70a30d070373fbb6c3 \
--hash=sha256:c61b89803a87a3b2a394089a7dadb79a6c64c89f2e8930cc187fec43b319f8d2 \
--hash=sha256:cdf80359b641185ae7e580afb9f88cf560298f309a38182972091165bfe1225d \
--hash=sha256:d93ebbff3dcf05274843ad8cf650b48ee634626e752c5d73614e5ec9df45f0ce \
--hash=sha256:db24d2738add6db19d66ca820479d2f8f96d3f5a13c223f27fa28dd2f268a4bd \
--hash=sha256:e0d20f27edfd6f35b388da2bdcd7769e4ffa374fef8994980ced26eb287e033a \
--hash=sha256:e2f3b5236079bc3e318a92bab2cc3f669cc32127075ab03ff61cacbae1c392b8 \
--hash=sha256:e481e54db8cec1457ee7c05f6d2329e3298a304a70d3b5e2e82e77170850b385 \
--hash=sha256:e5e5dc300a0ca8755ada1569f5caccfcdca28607dfb98b86a54996b288a8ebd3 \
--hash=sha256:ec2f525273528425ed2f51861b7b88955160cb95dddb17af0914077040aff4a5 \
--hash=sha256:f234ba3bb339ad17803009c8251f5ee65dcf283a380817fe486823b08b26383d \
--hash=sha256:f463598f9e51ccc04f0fe08500f9a0c3251a7086765350be418598b753b5561d \
--hash=sha256:f717944aee40e9f48776cf85b523bb376aa2d9255a268d6d643c57ab387e7264 \
--hash=sha256:fd0febae872a4042da44e972c070f0fd49a85a0a7727ab6b85425f74348be14e \
--hash=sha256:fec56c7d1b6a22c8f01557de3975d962ee40270b81b60d1cfdadf2a105d10e84
sqlalchemy==2.0.14 \
--hash=sha256:06f7e29e542c6f2dc751d4e9a8bdee1945226c0d501f8ee008baf5175604fb90 \
--hash=sha256:1ca00a7aca9636675a05b8ef99e09b9a6a680dfc346b5fe04e6ecc957a947501 \
--hash=sha256:21333b7ce04c3a57a7b17e19cd8a2ebeae4d58e3c97e57b0d6a2c626d7cddd3b \
--hash=sha256:243e580b477f0552424f9f9d281e5b37aa8be03e2261cfe992c60acd16fe218c \
--hash=sha256:252c49f86312e900591fb795d495a9e1b4199d0a799b55a6a5f46969068895c0 \
--hash=sha256:26025ba87797ac616b4823030adb2832e825ad8cdb4ac688e19ee93be69a42b6 \
--hash=sha256:281f0862483d89f169584f6b69dde1130d70612f4414c6a6167f690c7ac2a871 \
--hash=sha256:29935e0f3d91b7a97b9e635f3cf01d88cc7a0ace2e4686ec6cdbdfa04b0a2839 \
--hash=sha256:2c50b9d78362654d193ec03f4e524a1490abe9ac9d1001df60dd1e00d01d3d69 \
--hash=sha256:319184b851c0db141138a0a062fdd86b9eb5be4251a7d760d6465b92dd6c4e1e \
--hash=sha256:433467a5c4d0cf5f54f374574fb8a2d12c7f806c9a924307e1b816bd79f9ed3f \
--hash=sha256:465cf63f3a739f876ae0128e1308586f77516b5a574419614757d59682eb2feb \
--hash=sha256:49261a8f4bc0b41050d7719b93f1c93a8e19594aeeb252df93d61232f70c54d4 \
--hash=sha256:4dceffe226116aa16040ae36529fb1159f12c021d93de8de9f1261753a2ba2aa \
--hash=sha256:52169b1452bf6609c1b5fe95fba4d376f6e4551e7d73a5fd9216afbaf61ceed9 \
--hash=sha256:5364901aea8b5562a01d583c186bb5448913a8250f53617b5f592ca51f5c5e8a \
--hash=sha256:56b2b4bbfb5bf6c40d84109665a9f0c1c26b6f6280f1749ee5ddf3b82052386a \
--hash=sha256:7cb74468e646497daa743ab2344f7bb5e9fe97774654fa84879b38f8065ceb29 \
--hash=sha256:7e7527a1b16587c9b4660241ab5df334f693381ec47682b54293993aca8acfa9 \
--hash=sha256:7f02243efca602601bf5646ee627512b36e64068a3c88212e571b609bc7e128e \
--hash=sha256:82eb21e6aab4de898b6be89f5426454e4b5eee49792a44da87e602da89bb31dc \
--hash=sha256:888317fbebefbe87c933551f30864acd26366fad270d9be9dbb2ead32e446d83 \
--hash=sha256:8e1c6ed1e82c33917d7724ae2fe8e32715cb25b31ed467db2f507b21fd63cdb1 \
--hash=sha256:a824b15ef9596133d02364775c47ce173ea379179cc367e61d9d591e95843fdb \
--hash=sha256:ac104bb4390fdbf743f0de01cda40740b7da32f62304e89efb4e3300587636c6 \
--hash=sha256:afed9029db08e16187c7e2dcdfed99e9041499bdc4392589624b05d0a17b8c41 \
--hash=sha256:b3c7201fed64bfd83e90472ca4addce3be5dbaaf0cd427f61b1fb5425d89e714 \
--hash=sha256:bd213137ef398aed36e45c14d49057a3471f7200c07484ea5bbd89a91f488922 \
--hash=sha256:bec31cb4dcd924ff53b3bfdec1b565ccda062f0ebd1a325a247a1550782057de \
--hash=sha256:c1b8ea166cf63964dc11477f905869cc59b404f71a8e90033bd50843150584e0 \
--hash=sha256:c38bc0abfd93989afceeb79abb05f20ef0d56ebfd5eba5738e207ef50c1efd56 \
--hash=sha256:ce24180cf34ecd47a9a91d535b429deec14dc3d0cfa54d04979a3ebc60b1887d \
--hash=sha256:cf0b16edbebcd200c93e01cf0031b2af44d6ba374a8f8f7b120bc3db1df99cb7 \
--hash=sha256:d49ce7ac0713c820b5e2d6863ef87c22a8e1c950ce2778c69eb1327fc4b80dd2 \
--hash=sha256:d5c19b4a78126a263ecf01fcc1671344b5514392906cd46b70be74b73e543264 \
--hash=sha256:dabed709bd639e38c6b7f4ffc9a187d251dfc7636b5bc366408f5eadb631a558 \
--hash=sha256:e402263eca51ba18f3f8b06314a37b7a458496a65a515f5a25c7895423826a93 \
--hash=sha256:e422bec95850df641b05f2bd605d9995e01a66d55fa9fff6c79387dbdd8915af \
--hash=sha256:ec03e57ab555153195283017d804e0469b95bb012ecb19f6e2f0b22a3e60bdca \
--hash=sha256:f60461645af46e92bea54db9f3175c55bd9bceba02b133b77f700d7d9de57ead \
--hash=sha256:f851d8e2aaa0b0d07b89b7338441954e4d16d0eed5d140981e25cb5cfa259b3b
# via -r requirements.in
typing-extensions==4.5.0 \
--hash=sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb \

View file

@ -278,7 +278,7 @@ websocket-client==1.5.1 \
# kubernetes
# The following packages are considered to be unsafe in a requirements file:
setuptools==67.7.2 \
--hash=sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b \
--hash=sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990
setuptools==67.8.0 \
--hash=sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f \
--hash=sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102
# via kubernetes

View file

@ -254,9 +254,9 @@ urllib3==2.0.2 \
# via requests
# The following packages are considered to be unsafe in a requirements file:
setuptools==67.7.2 \
--hash=sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b \
--hash=sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990
setuptools==67.8.0 \
--hash=sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f \
--hash=sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102
# via
# acme
# certbot

View file

@ -397,9 +397,9 @@ zope-interface==6.0 \
# via gevent
# The following packages are considered to be unsafe in a requirements file:
setuptools==67.7.2 \
--hash=sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b \
--hash=sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990
setuptools==67.8.0 \
--hash=sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f \
--hash=sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102
# via
# gevent
# gunicorn

View file

@ -1,2 +1,2 @@
fastapi==0.95.1
fastapi==0.95.2
uvicorn[standard]==0.22.0

View file

@ -1,2 +1,2 @@
fastapi==0.95.1
fastapi==0.95.2
uvicorn[standard]==0.22.0

View file

@ -297,7 +297,6 @@ try:
core_plugins = {
"general": {
"order": 999,
"name": "General",
"description": "The general settings for the server",
"version": "0.1",
@ -332,7 +331,6 @@ try:
session.query(Plugins)
.with_entities(
Plugins.id,
Plugins.order,
Plugins.name,
Plugins.description,
Plugins.version,
@ -356,14 +354,13 @@ try:
exit(1)
if (
plugin.order != current_plugin[plugin.id]["order"]
or plugin.name != current_plugin[plugin.id]["name"]
plugin.name != current_plugin[plugin.id]["name"]
or plugin.description != current_plugin[plugin.id]["description"]
or plugin.version != current_plugin[plugin.id]["version"]
or plugin.stream != current_plugin[plugin.id]["stream"]
):
print(
f"❌ The {'external' if plugin.external else 'core'} plugin {plugin.name} (id: {plugin.id}) is in the database but is not correct, exiting ...\n{dumps({'order': plugin.order, 'name': plugin.name, 'description': plugin.description, 'version': plugin.version, 'stream': plugin.stream})} (database) != {dumps({'order': current_plugin[plugin.id]['order'], 'name': current_plugin[plugin.id]['name'], 'description': current_plugin[plugin.id]['description'], 'version': current_plugin[plugin.id]['version'], 'stream': current_plugin[plugin.id]['stream']})} (file)",
f"❌ The {'external' if plugin.external else 'core'} plugin {plugin.name} (id: {plugin.id}) is in the database but is not correct, exiting ...\n{dumps({'name': plugin.name, 'description': plugin.description, 'version': plugin.version, 'stream': plugin.stream})} (database) != {dumps({'name': current_plugin[plugin.id]['name'], 'description': current_plugin[plugin.id]['description'], 'version': current_plugin[plugin.id]['version'], 'stream': current_plugin[plugin.id]['stream']})} (file)",
flush=True,
)
exit(1)

View file

@ -1,4 +1,4 @@
sqlalchemy==2.0.13
sqlalchemy==2.0.14
psycopg2-binary==2.9.6
PyMySQL==1.0.3
cryptography==40.0.2

View file

@ -1,2 +1,2 @@
fastapi==0.95.1
fastapi==0.95.2
uvicorn[standard]==0.22.0

View file

@ -1 +1 @@
httpx==0.24.0
httpx==0.24.1

View file

@ -0,0 +1,27 @@
FROM python:3.11.3-alpine
# Install firefox and geckodriver
RUN apk add --no-cache --virtual .build-deps curl grep zip && \
apk add --no-cache firefox
# Installing geckodriver for firefox...
RUN GECKODRIVER_VERSION=`curl -i https://github.com/mozilla/geckodriver/releases/latest | grep -Po 'v[0-9]+.[0-9]+.[0-9]+'` && \
wget -O geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/$GECKODRIVER_VERSION/geckodriver-$GECKODRIVER_VERSION-linux64.tar.gz && \
tar -C /usr/local/bin -xzvf geckodriver.tar.gz && \
chmod +x /usr/local/bin/geckodriver && \
rm geckodriver.tar.gz
WORKDIR /tmp
COPY requirements.txt .
RUN MAKEFLAGS="-j $(nproc)" pip install --no-cache -r requirements.txt && \
rm -f requirements.txt
WORKDIR /opt/tests
COPY main.py .
EXPOSE 8080
ENTRYPOINT [ "python3", "main.py" ]

View file

@ -0,0 +1,9 @@
FROM redis:7-alpine
RUN apk add --no-cache bash openssl
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh
ENTRYPOINT [ "./entrypoint.sh" ]

View file

@ -0,0 +1,24 @@
version: "3.5"
services:
tests:
build: .
environment:
PYTHONUNBUFFERED: "1"
USE_REVERSE_SCAN: "no"
USE_ANTIBOT: "no"
BLACKLIST_IP: ""
REDIS_HOST: "bw-redis"
REDIS_PORT: "6379"
REDIS_DATABASE: "0"
REDIS_SSL: "no"
extra_hosts:
- "www.example.com:1.0.0.2"
networks:
bw-services:
ipv4_address: 1.0.0.3
networks:
bw-services:
external: true

View file

@ -0,0 +1,84 @@
version: "3.5"
services:
bw:
image: bunkerity/bunkerweb:1.5.0-beta
pull_policy: never
depends_on:
- bw-redis
labels:
- "bunkerweb.INSTANCE"
volumes:
- ./index.html:/var/www/html/index.html
environment:
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24 1.0.0.3"
HTTP_PORT: "80"
USE_BUNKERNET: "no"
BLACKLIST_IP_URLS: ""
LOG_LEVEL: "info"
SESSIONS_NAME: "test"
USE_REVERSE_SCAN: "no"
USE_ANTIBOT: "no"
USE_GREYLIST: "yes"
GREYLIST_IP: "0.0.0.0/0"
WHITELIST_COUNTRY: "AU"
# ? REDIS settings
USE_REDIS: "yes"
REDIS_HOST: "bw-redis"
REDIS_PORT: "6379"
REDIS_DATABASE: "0"
REDIS_SSL: "no"
networks:
bw-universe:
bw-services:
ipv4_address: 1.0.0.2
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.5.0-beta
pull_policy: never
depends_on:
- bw
- bw-docker
environment:
DOCKER_HOST: "tcp://bw-docker:2375"
LOG_LEVEL: "info"
networks:
- bw-universe
- bw-docker
bw-docker:
image: tecnativa/docker-socket-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
CONTAINERS: "1"
networks:
- bw-docker
bw-redis:
build:
context: .
dockerfile: Dockerfile.redis
environment:
REDIS_PORT: "6379"
REDIS_SSL: "no"
networks:
bw-services:
ipv4_address: 1.0.0.4
networks:
bw-universe:
name: bw-universe
ipam:
driver: default
config:
- subnet: 10.20.30.0/24
bw-services:
name: bw-services
ipam:
driver: default
config:
- subnet: 1.0.0.0/24
bw-docker:
name: bw-docker

View file

@ -0,0 +1,31 @@
#!/bin/bash
set -e
command="redis-server"
if [ "$REDIS_SSL" = "yes" ]; then
mkdir /tls
openssl genrsa -out /tls/ca.key 4096
openssl req \
-x509 -new -nodes -sha256 \
-key /tls/ca.key \
-days 365 \
-subj /CN=bw-redis/ \
-out /tls/ca.crt
openssl req \
-x509 -nodes -newkey rsa:4096 \
-keyout /tls/redis.key \
-out /tls/redis.pem \
-days 365 \
-subj /CN=bw-redis/
chmod -R 640 /tls
command+=" --tls-port ${REDIS_PORT:-6379} --port 0 --tls-cert-file /tls/redis.pem --tls-key-file /tls/redis.key --tls-ca-cert-file /tls/ca.crt --tls-auth-clients no"
else
command+=" --port ${REDIS_PORT:-6379}"
fi
$command

View file

371
tests/core/redis/main.py Normal file
View file

@ -0,0 +1,371 @@
from contextlib import suppress
from fastapi import FastAPI
from multiprocessing import Process
from os import getenv
from redis import Redis
from requests import get
from requests.exceptions import RequestException
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from time import sleep
from traceback import format_exc
from uvicorn import run
fastapi_proc = None
try:
redis_host = getenv("REDIS_HOST")
if not redis_host:
print("❌ Redis host is not set, exiting ...", flush=True)
exit(1)
redis_port = getenv("REDIS_PORT", "")
if not redis_port.isdigit():
print("❌ Redis port doesn't seem to be a number, exiting ...", flush=True)
exit(1)
redis_port = int(redis_port)
redis_db = getenv("REDIS_DATABASE", "")
if not redis_db.isdigit():
print("❌ Redis database doesn't seem to be a number, exiting ...", flush=True)
exit(1)
redis_db = int(redis_db)
redis_ssl = getenv("REDIS_SSL", "no") == "yes"
print(
f" Trying to connect to Redis with the following parameters:\nhost: {redis_host}\nport: {redis_port}\ndb: {redis_db}\nssl: {redis_ssl}",
flush=True,
)
redis_client = Redis(
host=redis_host,
port=redis_port,
db=redis_db,
ssl=redis_ssl,
socket_timeout=1,
ssl_cert_reqs=None,
)
if not redis_client.ping():
print("❌ Redis is not reachable, exiting ...", flush=True)
exit(1)
use_reverse_scan = getenv("USE_REVERSE_SCAN", "no") == "yes"
if use_reverse_scan:
print(" Testing Reverse Scan, starting FastAPI ...", flush=True)
app = FastAPI()
fastapi_proc = Process(
target=run, args=(app,), kwargs=dict(host="0.0.0.0", port=8080)
)
fastapi_proc.start()
sleep(2)
print(
" FastAPI started, sending a request to http://www.example.com ...",
flush=True,
)
response = get(
"http://www.example.com",
headers={"Host": "www.example.com"},
)
if response.status_code != 403:
response.raise_for_status()
print("❌ The request was not blocked, exiting ...", flush=True)
exit(1)
sleep(0.5)
print(" The request was blocked, checking Redis ...", flush=True)
key_value = redis_client.get("plugin_reverse_scan_1.0.0.3:8080")
if key_value is None:
print(
f'❌ The Reverse Scan key ("plugin_reverse_scan_1.0.0.3:8080") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
elif key_value != b"open":
print(
f'❌ The Reverse Scan key ("plugin_reverse_scan_1.0.0.3:8080") was found, but the value is not "open" ({key_value.decode()}), exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The Reverse Scan key was found, the value is {key_value.decode()}",
flush=True,
)
exit(0)
use_antibot = getenv("USE_ANTIBOT", "no") != "no"
if use_antibot:
print(" Testing Antibot ...", flush=True)
firefox_options = Options()
firefox_options.add_argument("--headless")
print(" Starting Firefox ...", flush=True)
with webdriver.Firefox(options=firefox_options) as driver:
driver.delete_all_cookies()
driver.maximize_window()
print(" Navigating to http://www.example.com ...", flush=True)
driver.get("http://www.example.com")
sleep(0.5)
print(" Checking Redis ...", flush=True)
keys = redis_client.keys("sessions_:test:*")
if not keys:
print(
f"❌ No Antibot keys were found, exiting ...\nkeys: {redis_client.keys()}",
flush=True,
)
exit(1)
key_value = redis_client.get(keys[0])
if key_value is None:
print(
f"❌ The Antibot key ({keys[0].decode()}) was not found, exiting ...\nkeys: {redis_client.keys()}",
flush=True,
)
exit(1)
print(
f"✅ The Antibot key was found, the value is {key_value.decode()}",
flush=True,
)
exit(0)
print(
" Sending a request to http://www.example.com/?id=/etc/passwd ...",
flush=True,
)
response = get(
"http://www.example.com/?id=/etc/passwd",
headers={"Host": "www.example.com"},
)
if response.status_code != 403:
response.raise_for_status()
print("❌ The request was not blocked, exiting ...", flush=True)
exit(1)
sleep(0.5)
print(" The request was blocked, checking Redis ...", flush=True)
key_value = redis_client.get("plugin_bad_behavior_1.0.0.3")
if key_value is None:
print(
f'❌ The Bad Behavior key ("plugin_bad_behavior_1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The Bad Behavior key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Sending another request to http://www.example.com/?id=/etc/passwd ...",
flush=True,
)
response = get(
"http://www.example.com/?id=/etc/passwd",
headers={"Host": "www.example.com"},
)
if response.status_code != 403:
response.raise_for_status()
print("❌ The request was not blocked, exiting ...", flush=True)
exit(1)
sleep(0.5)
second_key_value = redis_client.get("plugin_bad_behavior_1.0.0.3")
if second_key_value <= key_value:
print(
f'❌ The Bad Behavior key ("plugin_bad_behavior_1.0.0.3") was not incremented, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The Bad Behavior key was incremented, the value is {second_key_value.decode()}",
flush=True,
)
print(
" Sending requests to http://www.example.com until we reach the limit ...",
flush=True,
)
status_code = 0
while status_code != 429:
response = get(
"http://www.example.com",
headers={"Host": "www.example.com"},
)
if response.status_code not in (200, 429):
response.raise_for_status()
status_code = response.status_code
sleep(0.5)
key_value = redis_client.get("plugin_limit_www.example.com1.0.0.3/")
if key_value is None:
print(
f'❌ The limit key ("plugin_limit_www.example.com1.0.0.3/") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The limit key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Checking if the country key was created and has the correct value ...",
flush=True,
)
key_value = redis_client.get("plugin_country_www.example.com1.0.0.3")
if key_value is None:
print(
f'❌ The country key ("plugin_country_www.example.com1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The country key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Checking if the whitelist key was created and has the correct value ...",
flush=True,
)
key_value = redis_client.get("plugin_whitelist_www.example.comip1.0.0.3")
if key_value is None:
print(
f'❌ The whitelist key ("plugin_whitelist_www.example.comip1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
if key_value != b"ok":
print(
f'❌ The whitelist key ("plugin_whitelist_www.example.comip1.0.0.3") was found, but the value is not "ok" ({key_value.decode()}), exiting ...\nkeys: {redis_client.keys()}',
)
print(
f"✅ The whitelist key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Checking if the blacklist key was created and has the correct value ...",
flush=True,
)
key_value = redis_client.get("plugin_blacklist_www.example.comip1.0.0.3")
if key_value is None:
print(
f'❌ The blacklist key ("plugin_blacklist_www.example.comip1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
if key_value != b"ok":
print(
f'❌ The blacklist key ("plugin_blacklist_www.example.comip1.0.0.3") was found, but the value is not "ok" ({key_value.decode()}), exiting ...\nkeys: {redis_client.keys()}',
)
print(
f"✅ The blacklist key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Checking if the greylist key was created and has the correct value ...",
flush=True,
)
key_value = redis_client.get("plugin_greylist_www.example.comip1.0.0.3")
if key_value is None:
print(
f'❌ The greylist key ("plugin_greylist_www.example.comip1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
if key_value != b"ip":
print(
f'❌ The greylist key ("plugin_greylist_www.example.comip1.0.0.3") was found, but the value is not "ip" ({key_value.decode()}), exiting ...\nkeys: {redis_client.keys()}',
)
print(
f"✅ The greylist key was found, the value is {key_value.decode()}",
flush=True,
)
print(
" Checking if the dnsbl keys were created ...",
flush=True,
)
key_value = redis_client.get("plugin_dnsbl_www.example.com1.0.0.3")
if key_value is None:
print(
f'❌ The dnsbl key ("plugin_dnsbl_www.example.com1.0.0.3") was not found, exiting ...\nkeys: {redis_client.keys()}',
flush=True,
)
exit(1)
print(
f"✅ The dnsbl key was found, the value is {key_value.decode()}",
flush=True,
)
except SystemExit as e:
exit(e.code)
except:
print(f"❌ Something went wrong, exiting ...\n{format_exc()}", flush=True)
exit(1)
finally:
if fastapi_proc:
fastapi_proc.terminate()

View file

@ -0,0 +1,5 @@
requests==2.30.0
redis==4.5.5
fastapi==0.95.2
uvicorn[standard]==0.22.0
selenium==4.9.1

138
tests/core/redis/test.sh Normal file → Executable file
View file

@ -1 +1,137 @@
# TODO
#!/bin/bash
echo "🧰 Building redis stack ..."
# Starting stack
docker compose pull bw-docker
if [ $? -ne 0 ] ; then
echo "🧰 Pull failed ❌"
exit 1
fi
echo "🧰 Building custom redis image ..."
docker compose build bw-redis
if [ $? -ne 0 ] ; then
echo "🧰 Build failed ❌"
exit 1
fi
echo "🧰 Building tests images ..."
docker compose -f docker-compose.test.yml build
if [ $? -ne 0 ] ; then
echo "🧰 Build failed ❌"
exit 1
fi
manual=0
end=0
cleanup_stack () {
exit_code=$?
if [[ $end -eq 1 || $exit_code = 1 ]] || [[ $end -eq 0 && $exit_code = 0 ]] && [ $manual = 0 ] ; then
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_REVERSE_SCAN: "yes"@USE_REVERSE_SCAN: "no"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_ANTIBOT: "cookie"@USE_ANTIBOT: "no"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@BLACKLIST_IP: "0\.0\.0\.0/0"@BLACKLIST_IP: ""@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_PORT: "[0-9]*"@REDIS_PORT: "6379"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_DATABASE: "1"@REDIS_DATABASE: "0"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_SSL: "yes"@REDIS_SSL: "no"@' {} \;
if [[ $end -eq 1 && $exit_code = 0 ]] ; then
return
fi
fi
echo "🧰 Cleaning up current stack ..."
docker compose down -v --remove-orphans 2>/dev/null
if [ $? -ne 0 ] ; then
echo "🧰 Down failed ❌"
exit 1
fi
echo "🧰 Cleaning up current stack done ✅"
}
# Cleanup stack on exit
trap cleanup_stack EXIT
for test in "activated" "reverse_scan" "antibot" "tweaked"
do
if [ "$test" = "activated" ] ; then
echo "🧰 Running tests with redis with default values ..."
elif [ "$test" = "reverse_scan" ] ; then
echo "🧰 Running tests with redis with reverse scan activated ..."
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_REVERSE_SCAN: "no"@USE_REVERSE_SCAN: "yes"@' {} \;
elif [ "$test" = "antibot" ] ; then
echo "🧰 Running tests with redis with antibot cookie activated ..."
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_REVERSE_SCAN: "yes"@USE_REVERSE_SCAN: "no"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_ANTIBOT: "no"@USE_ANTIBOT: "cookie"@' {} \;
elif [ "$test" = "tweaked" ] ; then
echo "🧰 Running tests with redis' settings tweaked ..."
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_ANTIBOT: "cookie"@USE_ANTIBOT: "no"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_PORT: "[0-9]*"@REDIS_PORT: "6380"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_DATABASE: "0"@REDIS_DATABASE: "1"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@REDIS_SSL: "no"@REDIS_SSL: "yes"@' {} \;
fi
echo "🧰 Starting stack ..."
docker compose up -d 2>/dev/null
if [ $? -ne 0 ] ; then
echo "🧰 Up failed, retrying ... ⚠️"
manual=1
cleanup_stack
manual=0
docker compose up -d 2>/dev/null
if [ $? -ne 0 ] ; then
echo "🧰 Up failed ❌"
exit 1
fi
fi
# Check if stack is healthy
echo "🧰 Waiting for stack to be healthy ..."
i=0
while [ $i -lt 120 ] ; do
containers=("redis-bw-1" "redis-bw-scheduler-1")
healthy="true"
for container in "${containers[@]}" ; do
check="$(docker inspect --format "{{json .State.Health }}" $container | grep "healthy")"
if [ "$check" = "" ] ; then
healthy="false"
break
fi
done
if [ "$healthy" = "true" ] ; then
echo "🧰 Docker stack is healthy ✅"
break
fi
sleep 1
i=$((i+1))
done
if [ $i -ge 120 ] ; then
docker compose logs
echo "🧰 Docker stack is not healthy ❌"
exit 1
fi
# Start tests
docker compose -f docker-compose.test.yml up --abort-on-container-exit --exit-code-from tests 2>/dev/null
if [ $? -ne 0 ] ; then
echo "🧰 Test \"$test\" failed ❌"
echo "🛡️ Showing BunkerWeb and BunkerWeb Scheduler logs ..."
docker compose logs bw bw-scheduler
exit 1
else
echo "🧰 Test \"$test\" succeeded ✅"
fi
manual=1
cleanup_stack
manual=0
echo " "
done
end=1
echo "🧰 Tests are done ! ✅"

View file

@ -1,3 +1,3 @@
requests==2.30.0
fastapi==0.95.1
fastapi==0.95.2
uvicorn[standard]==0.22.0

View file

@ -1,2 +1,2 @@
fastapi==0.95.1
fastapi==0.95.2
uvicorn[standard]==0.22.0