Merge pull request #894 from bunkerity/dev

Merge branch "dev" into branch "staging"
This commit is contained in:
Théophile Diot 2024-01-30 18:22:21 +01:00 committed by GitHub
commit ec0aeb8d7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
86 changed files with 7161 additions and 340 deletions

View file

@ -35,12 +35,12 @@ jobs:
python -m pip install --no-cache-dir --require-hashes -r src/common/db/requirements.txt
echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV
- name: Initialize CodeQL
uses: github/codeql-action/init@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/init@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql.yml
setup-python-dependencies: false
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/analyze@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
category: "/language:${{matrix.language}}"

View file

@ -25,6 +25,6 @@ jobs:
results_format: sarif
publish_results: true
- name: "Upload SARIF results to code scanning"
uses: github/codeql-action/upload-sarif@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/upload-sarif@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
sarif_file: results.sarif

View file

@ -64,7 +64,7 @@ RUN apk add --no-cache bash && \
chmod 750 cli/main.py helpers/*.sh /usr/bin/bwcli autoconf/main.py deps/python/bin/*
# Fix CVEs
RUN apk add --no-cache "libcrypto3>=3.1.4-r3" "libssl3>=3.1.4-r3" "sqlite-libs>=3.41.2-r3"
RUN apk add --no-cache "libcrypto3>=3.1.4-r5" "libssl3>=3.1.4-r5" "sqlite-libs>=3.41.2-r3"
VOLUME /data /etc/nginx

View file

@ -258,10 +258,15 @@ api.global.GET["^/bans$"] = function(self)
"can't access ttl " .. k .. " from datastore : " .. ttl
)
end
local ban_data = decode(result)
local ban =
local ban_data
ok, ban_data = pcall(decode, result)
if not ok then
ban_data = { reason = result, date = -1 }
end
table.insert(
data,
{ ip = k:sub(9, #k), reason = ban_data["reason"], date = ban_data["date"], exp = math.floor(ttl) }
table.insert(data, ban)
)
end
end
return self:response(HTTP_OK, "success", data)

View file

@ -317,7 +317,11 @@ utils.get_reason = function(ctx)
end
local banned, _ = datastore:get("bans_ip_" .. ip)
if banned then
return decode(banned)["reason"], {}
local ok, ban_data = pcall(decode, banned)
if ok then
banned = ban_data["reason"]
end
return banned, {}
end
-- unknown
if ngx.status == utils.get_deny_status() then
@ -642,12 +646,16 @@ utils.is_banned = function(ip)
if not result and err ~= "not found" then
return nil, "datastore:get() error : " .. result
elseif result and err ~= "not found" then
local ok, ttl = datastore:ttl("bans_ip_" .. ip)
local ban_data = decode(result)
if not ok then
return true, ban_data["reason"], -1
local ok, ban_data = pcall(decode, result)
if ok then
result = ban_data["reason"]
end
return true, ban_data["reason"], ttl
local ttl
ok, ttl = datastore:ttl("bans_ip_" .. ip)
if not ok then
return true, result, -1
end
return true, result, ttl
end
-- Redis case
local use_redis, err = utils.get_variable("USE_REDIS", false)
@ -694,7 +702,12 @@ utils.is_banned = function(ip)
if not ok then
return nil, "datastore:set() error : " .. err
end
return true, decode(data[1])["reason"], data[2]
local ban_data
ok, ban_data = pcall(decode, data[1])
if ok then
data[1] = ban_data["reason"]
end
return true, data[1], data[2]
end
clusterstore:close()
return false, "not banned"

View file

@ -258,7 +258,13 @@ class CLI(ApiCaller):
cli_str += "No ban found\n"
for ban in bans:
cli_str += f"- {ban['ip']} ; banned the {datetime.fromtimestamp(ban['date']).strftime('%d-%m-%Y at %H:%M:%S')} for {format_remaining_time(ban['exp'])} remaining with reason \"{ban.get('reason', 'no reason given')}\"\n"
banned_date = ""
remaining = "for eternity"
if ban["date"] != -1:
banned_date = f"the {datetime.fromtimestamp(ban['date']).strftime('%d-%m-%Y at %H:%M:%S')} "
if ban["exp"] != -1:
remaining = f"for {format_remaining_time(ban['exp'])} remaining"
cli_str += f"- {ban['ip']} ; banned {banned_date}{remaining} with reason \"{ban.get('reason', 'no reason given')}\"\n"
cli_str += "\n"
return True, cli_str

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,69 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ antibot_info or "Anti-bot technology is designed to detect and
mitigate suspicious or malicious bots, preventing them from reaching an
organization's websites or IT ecosystem." }}
</p>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
Challenges
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ antibot_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-sky-500 mx-0.5"
>total number</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-sky-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-75 leading-none text-lg relative fill-white"
>
<path
d="M11.7 2.805a.75.75 0 0 1 .6 0A60.65 60.65 0 0 1 22.83 8.72a.75.75 0 0 1-.231 1.337 49.948 49.948 0 0 0-9.902 3.912l-.003.002c-.114.06-.227.119-.34.18a.75.75 0 0 1-.707 0A50.88 50.88 0 0 0 7.5 12.173v-.224c0-.131.067-.248.172-.311a54.615 54.615 0 0 1 4.653-2.52.75.75 0 0 0-.65-1.352 56.123 56.123 0 0 0-4.78 2.589 1.858 1.858 0 0 0-.859 1.228 49.803 49.803 0 0 0-4.634-1.527.75.75 0 0 1-.231-1.337A60.653 60.653 0 0 1 11.7 2.805Z"
/>
<path
d="M13.06 15.473a48.45 48.45 0 0 1 7.666-3.282c.134 1.414.22 2.843.255 4.284a.75.75 0 0 1-.46.711 47.87 47.87 0 0 0-8.105 4.342.75.75 0 0 1-.832 0 47.87 47.87 0 0 0-8.104-4.342.75.75 0 0 1-.461-.71c.035-1.442.121-2.87.255-4.286.921.304 1.83.634 2.726.99v1.27a1.5 1.5 0 0 0-.14 2.508c-.09.38-.222.753-.397 1.11.452.213.901.434 1.346.66a6.727 6.727 0 0 0 .551-1.607 1.5 1.5 0 0 0 .14-2.67v-.645a48.549 48.549 0 0 1 3.44 1.667 2.25 2.25 0 0 0 2.12 0Z"
/>
<path
d="M4.462 19.462c.42-.419.753-.89 1-1.395.453.214.902.435 1.347.662a6.742 6.742 0 0 1-1.286 1.794.75.75 0 0 1-1.06-1.06Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,65 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ authbasic_info or "Basic Auth is a method for an HTTP user agent
(e.g. a web browser) to provide a user name and password when making a
request." }}
</p>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
AUTH BASIC
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ authbasic_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5"
>passed credentials</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-green-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="stroke-none scale-[0.6] leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M15.75 1.5a6.75 6.75 0 0 0-6.651 7.906c.067.39-.032.717-.221.906l-6.5 6.499a3 3 0 0 0-.878 2.121v2.818c0 .414.336.75.75.75H6a.75.75 0 0 0 .75-.75v-1.5h1.5A.75.75 0 0 0 9 19.5V18h1.5a.75.75 0 0 0 .53-.22l2.658-2.658c.19-.189.517-.288.906-.22A6.75 6.75 0 1 0 15.75 1.5Zm0 3a.75.75 0 0 0 0 1.5A2.25 2.25 0 0 1 18 8.25a.75.75 0 0 0 1.5 0 3.75 3.75 0 0 0-3.75-3.75Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,119 @@
{% extends "base.html" %} {% block content %} {% set items = [{"code" : 400,
"count" : 24}, {"code" : 403, "count" : 845}, {"code" : 402, "count" : 12}]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div class="col-span-12 grid grid-cols-12 gap-4">
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ bad_behavior_info or "Ban IP generating too much 'bad' HTTP status
code in a period of time." }}
</p>
</div>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
BAD BEHAVIOR
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ bad_behavior_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5"
>total ip bans</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
aria-label="version"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="stroke-none scale-75 leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="m6.72 5.66 11.62 11.62A8.25 8.25 0 0 0 6.72 5.66Zm10.56 12.68L5.66 6.72a8.25 8.25 0 0 0 11.62 11.62ZM5.105 5.106c3.807-3.808 9.98-3.808 13.788 0 3.808 3.807 3.808 9.98 0 13.788-3.807 3.808-9.98 3.808-13.788 0-3.808-3.807-3.808-9.98 0-13.788Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
{% if items|length != 0 %}
<div
class="2xl:col-span-4 3xl:col-span-3 w-full md:max-w-[350px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
BAD BEHAVIOR LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[250px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-6 m-0 pb-2 border-b border-gray-400"
>
Error code
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-6 m-0 pb-2 border-b border-gray-400"
>
Count
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-6 m-0 my-1"
>
{{item['code']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-6 m-0 my-1"
>
{{item['count']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,236 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ blacklist_info or "Deny access based on internal and external
IP/network/rDNS/ASN blacklists." }}
</p>
</div>
</div>
<!-- end info -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
URL
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ blacklist_url_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M19.902 4.098a3.75 3.75 0 0 0-5.304 0l-4.5 4.5a3.75 3.75 0 0 0 1.035 6.037.75.75 0 0 1-.646 1.353 5.25 5.25 0 0 1-1.449-8.45l4.5-4.5a5.25 5.25 0 1 1 7.424 7.424l-1.757 1.757a.75.75 0 1 1-1.06-1.06l1.757-1.757a3.75 3.75 0 0 0 0-5.304Zm-7.389 4.267a.75.75 0 0 1 1-.353 5.25 5.25 0 0 1 1.449 8.45l-4.5 4.5a5.25 5.25 0 1 1-7.424-7.424l1.757-1.757a.75.75 0 1 1 1.06 1.06l-1.757 1.757a3.75 3.75 0 1 0 5.304 5.304l4.5-4.5a3.75 3.75 0 0 0-1.035-6.037.75.75 0 0 1-.354-1Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
IP
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ blacklist_ip_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-lime-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
d="M3.53 2.47a.75.75 0 0 0-1.06 1.06l18 18a.75.75 0 1 0 1.06-1.06l-18-18ZM20.25 5.507v11.561L5.853 2.671c.15-.043.306-.075.467-.094a49.255 49.255 0 0 1 11.36 0c1.497.174 2.57 1.46 2.57 2.93ZM3.75 21V6.932l14.063 14.063L12 18.088l-7.165 3.583A.75.75 0 0 1 3.75 21Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
RDNS
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ blacklist_rdns_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-indigo-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M11.625 16.5a1.875 1.875 0 1 0 0-3.75 1.875 1.875 0 0 0 0 3.75Z"
/>
<path
fill-rule="evenodd"
d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm6 16.5c.66 0 1.277-.19 1.797-.518l1.048 1.048a.75.75 0 0 0 1.06-1.06l-1.047-1.048A3.375 3.375 0 1 0 11.625 18Z"
clip-rule="evenodd"
/>
<path
d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
ASN
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ blacklist_asn_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-blue-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
User Agent
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ blacklist_user_agent_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-amber-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,215 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- status -->
<div class="col-span-12 grid grid-cols-12 gap-4">
{% if bunkernet_status %}
<div
class="col-span-12 md:col-span-6 2xl:col-span-3 3xl:col-span-2 w-fit h-fit transition hover:scale-102 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="mx-1 flex justify-start items-center">
<h5 class="mb-0 font-bold dark:text-white/90 mr-4">STATUS</h5>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 fill-green-500"
>
<path
fill-rule="evenodd"
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z"
clip-rule="evenodd"
/>
</svg>
</div>
<p
class="mx-1 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
Active
</p>
</div>
{% else %}
<div
class="col-span-12 md:col-span-6 2xl:col-span-3 3xl:col-span-2 w-fit h-fit transition hover:scale-102 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="mx-1 flex justify-start items-center">
<h5 class="mb-0 font-bold dark:text-white/90 mr-4">STATUS</h5>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 fill-red-500"
>
<path
fill-rule="evenodd"
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z"
clip-rule="evenodd"
/>
</svg>
</div>
<p
class="mx-1 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
Inactive
</p>
</div>
{% endif %}
<!-- end status -->
</div>
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ bunkernet_info or "BunkerNet is a crowdsourced database of malicious
requests shared between all BunkerWeb instances over the world. " }}
</p>
</div>
</div>
<!-- end info -->
<!-- test-->
<div
class="transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">TEST</h5>
<p
class="my-2 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80 text-center"
>
Use the next button to ping BunkerNet (better change limit request
settings before).
</p>
<div class="flex justify-center mt-4">
<button type="button" class="edit-btn text-sm" onclick="ping()">
Ping BunkerNet
</button>
</div>
<hr
class="h-px mx-0 mt-3 mb-2 bg-transparent bg-gradient-to-r from-transparent via-black/40 to-transparent dark:bg-gradient-to-r dark:from-transparent dark:via-white dark:to-transparent"
/>
<div id="response-div" class="flex justify-center items-center">
<div id="no-test" class="flex justify-center items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-gray-600"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-gray-600 text-base uppercase">
UNKNOWN
</p>
</div>
<div
class="hidden flex justify-center items-center"
id="response-success"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-green-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-green-500 text-base uppercase">
SUCCESS
</p>
</div>
<div class="hidden flex justify-center items-center" id="response-failed">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-red-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-red-500 text-base uppercase">
FAILED
</p>
</div>
<div class="hidden flex justify-center items-center" id="response-none">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-red-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M18.364 18.364A9 9 0 0 0 5.636 5.636m12.728 12.728A9 9 0 0 1 5.636 5.636m12.728 12.728L5.636 5.636"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-red-500 text-base uppercase">
FAILED
</p>
</div>
</div>
</div>
<!-- end test -->
<script async>
function ping() {
let data = new FormData();
data.set("csrf_token", "{{ csrf_token() }}");
let xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url_for('plugins') }}/bunkernet", true);
xhr.send(data);
xhr.onload = function () {
document.getElementById("no-test").classList.add("hidden");
if (xhr.status == 200) {
document.getElementById("response-failed").classList.remove("hidden");
document.getElementById("response-none").classList.add("hidden");
document.getElementById("response-success").classList.add("hidden");
} else if (xhr.status == 403) {
document
.getElementById("response-success")
.classList.remove("hidden");
document.getElementById("response-none").classList.add("hidden");
document.getElementById("response-failed").classList.add("hidden");
} else {
document.getElementById("response-none").classList.remove("hidden");
document.getElementById("response-success").classList.add("hidden");
document.getElementById("response-failed").classList.add("hidden");
}
};
}
</script>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,66 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ cors_info or "Cross-Origin Resource Sharing lets you manage how your
service can be contacted from different origins." }}
</p>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
CORS
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ cors_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5"
>request blocked</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="scale-75 leading-none text-lg relative fill-red-700 stroke-white"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,111 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div class="col-span-12 grid grid-cols-12 gap-4">
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ country_info or "The country security feature allows you to apply
policy based on the country of the IP address of clients (blacklist /
whitelist)." }}
</p>
</div>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
Country
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ country_blacklist_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5"
>blacklist request blocked</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="scale-75 leading-none text-lg relative fill-red-700 stroke-white"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
Country
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ country_blacklist_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5"
>whitelist request passed</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-green-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-75 leading-none text-lg relative stroke-green-700 fill-white"
>
<path
fill-rule="evenodd"
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,87 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"server_name" :
"www.example.com", "cn" : "Let's encrypt", "expire" : "15/11/2024"},
{"server_name" : "app1.com", "cn" : "Self signed", "expire" : "11/01/2028"},
{"server_name" : "test.2.fr", "cn" : "Default", "expire" : "31/08/2035"} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ custom_certificate_info or "Custom certificates allow you to get
HTTPS / SSL / TLS on your requests." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[600px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
CUSTOM CERTIFICATE LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[400px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Server name
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
CN
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Expiry date
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['server_name']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['cn']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['expire']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,107 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div class="col-span-12 grid grid-cols-12 gap-4">
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ db_info or "BunkerWeb securely stores its current configuration in
a backend database, which contains essential data for smooth
operation." }}
</p>
</div>
</div>
</div>
<!-- end info -->
<!-- driver-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">DB</h5>
<div class="mx-1 flex justify-start items-center mt-4">
<p
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
>
DRIVER
<span
class="ml-1 font-semibold transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ db_driver or "unknown" }}
</span>
</p>
</div>
<div class="mx-1 flex justify-start items-center mt-1 mb-4">
<p
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
>
VERSION
<span
class="ml-1 font-semibold transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ db_version or "unknown" }}
</span>
</p>
</div>
</div>
<!-- end driver -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
SIZE
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ db_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-sky-500 mx-0.5">
MB used on database
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-sky-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M21 6.375c0 2.692-4.03 4.875-9 4.875S3 9.067 3 6.375 7.03 1.5 12 1.5s9 2.183 9 4.875Z"
/>
<path
d="M12 12.75c2.685 0 5.19-.586 7.078-1.609a8.283 8.283 0 0 0 1.897-1.384c.016.121.025.244.025.368C21 12.817 16.97 15 12 15s-9-2.183-9-4.875c0-.124.009-.247.025-.368a8.285 8.285 0 0 0 1.897 1.384C6.809 12.164 9.315 12.75 12 12.75Z"
/>
<path
d="M12 16.5c2.685 0 5.19-.586 7.078-1.609a8.282 8.282 0 0 0 1.897-1.384c.016.121.025.244.025.368 0 2.692-4.03 4.875-9 4.875s-9-2.183-9-4.875c0-.124.009-.247.025-.368a8.284 8.284 0 0 0 1.897 1.384C6.809 15.914 9.315 16.5 12 16.5Z"
/>
<path
d="M12 20.25c2.685 0 5.19-.586 7.078-1.609a8.282 8.282 0 0 0 1.897-1.384c.016.121.025.244.025.368 0 2.692-4.03 4.875-9 4.875s-9-2.183-9-4.875c0-.124.009-.247.025-.368a8.284 8.284 0 0 0 1.897 1.384C6.809 19.664 9.315 20.25 12 20.25Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,97 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"server_name" :
"www.example.com", "status" : "ok"}, {"server_name" : "app1.com", "status" :
"ok"}, {"server_name" : "test.2.fr", "status" : "ko"} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ dnsbl_info or "Deny access based on external DNSBL servers." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[600px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">DNSBL LIST</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[400px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-8 m-0 pb-2 border-b border-gray-400"
>
Server name
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Status
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-8 m-0 my-1"
>
{{item['server_name']}}
</p>
{% if item['status'] == "ko"%}
<div class="col-span-4 ml-2 m-0 my-1">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-6 h-6 fill-red-500"
>
<path
fill-rule="evenodd"
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z"
clip-rule="evenodd"
/>
</svg>
</div>
{% else %}
<div class="col-span-4 ml-2 m-0 my-1">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-6 h-6 fill-green-500"
>
<path
fill-rule="evenodd"
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z"
clip-rule="evenodd"
/>
</svg>
</div>
{% endif %}
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,71 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"count" : 74,
"code" : "403"}, {"count" : 82, "code" : "404"}, {"count" : "32", "code" :
"400"} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ dnsbl_info or "Deny access based on external DNSBL servers." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full md:max-w-[400px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">ERRORS LIST</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[350px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-8 m-0 pb-2 border-b border-gray-400"
>
Code error
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Count
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="ml-1 dark:text-gray-400 dark:opacity-80 text-sm col-span-8 m-0 my-1"
>
{{item['code']}}
</p>
<p
class="ml-1 dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['count']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,236 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ greylist_info or "Allow access while keeping security features
based on internal and external IP/network/rDNS/ASN greylists. " }}
</p>
</div>
</div>
<!-- end info -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
URL
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ greylist_url_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M19.902 4.098a3.75 3.75 0 0 0-5.304 0l-4.5 4.5a3.75 3.75 0 0 0 1.035 6.037.75.75 0 0 1-.646 1.353 5.25 5.25 0 0 1-1.449-8.45l4.5-4.5a5.25 5.25 0 1 1 7.424 7.424l-1.757 1.757a.75.75 0 1 1-1.06-1.06l1.757-1.757a3.75 3.75 0 0 0 0-5.304Zm-7.389 4.267a.75.75 0 0 1 1-.353 5.25 5.25 0 0 1 1.449 8.45l-4.5 4.5a5.25 5.25 0 1 1-7.424-7.424l1.757-1.757a.75.75 0 1 1 1.06 1.06l-1.757 1.757a3.75 3.75 0 1 0 5.304 5.304l4.5-4.5a3.75 3.75 0 0 0-1.035-6.037.75.75 0 0 1-.354-1Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
IP
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ greylist_ip_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-lime-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
d="M3.53 2.47a.75.75 0 0 0-1.06 1.06l18 18a.75.75 0 1 0 1.06-1.06l-18-18ZM20.25 5.507v11.561L5.853 2.671c.15-.043.306-.075.467-.094a49.255 49.255 0 0 1 11.36 0c1.497.174 2.57 1.46 2.57 2.93ZM3.75 21V6.932l14.063 14.063L12 18.088l-7.165 3.583A.75.75 0 0 1 3.75 21Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
RDNS
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ greylist_rdns_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-indigo-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M11.625 16.5a1.875 1.875 0 1 0 0-3.75 1.875 1.875 0 0 0 0 3.75Z"
/>
<path
fill-rule="evenodd"
d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm6 16.5c.66 0 1.277-.19 1.797-.518l1.048 1.048a.75.75 0 0 0 1.06-1.06l-1.047-1.048A3.375 3.375 0 1 0 11.625 18Z"
clip-rule="evenodd"
/>
<path
d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
ASN
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ greylist_asn_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-blue-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
User Agent
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ greylist_user_agent_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5">
denied
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-amber-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,86 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"server_name" :
"www.example.com", "cn" : "Let's encrypt", "expire" : "15/11/2024"},
{"server_name" : "app1.com", "cn" : "Self signed", "expire" : "11/01/2028"},
{"server_name" : "test.2.fr", "cn" : "Default", "expire" : "31/08/2035"} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ lets_encrypt_info or "Let's Encrypt certificates for secure HTTP
requests." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[600px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
LET'S ENCRYPT LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[400px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Server name
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
CN
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Expiry date
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['server_name']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['cn']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['expire']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,74 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"url" :
"http://www.example.com", "count" : 24},{"url" : "http://www.example.com",
"count" : 24} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ limit_info or "Limit maximum number of requests and connections." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[600px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
LIMIT AND REQUEST LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[500px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-8 m-0 pb-2 border-b border-gray-400"
>
URL
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Count
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="ml-1 dark:text-gray-400 dark:opacity-80 text-sm col-span-8 m-0 my-1"
>
{{item['url']}}
</p>
<p
class="ml-1 dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['count']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,108 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ misc_info or "Miscellaneous settings (methods, servers...)." }}
</p>
</div>
</div>
<!-- end info -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
DEFAULT SERVER DISABLED
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ default_server_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-sky-500 mx-0.5">
total
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-orange-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.55] leading-none text-lg relative fill-white"
>
<path
d="M4.08 5.227A3 3 0 0 1 6.979 3H17.02a3 3 0 0 1 2.9 2.227l2.113 7.926A5.228 5.228 0 0 0 18.75 12H5.25a5.228 5.228 0 0 0-3.284 1.153L4.08 5.227Z"
/>
<path
fill-rule="evenodd"
d="M5.25 13.5a3.75 3.75 0 1 0 0 7.5h13.5a3.75 3.75 0 1 0 0-7.5H5.25Zm10.5 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm3.75-.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
DISALLOWED METHODS
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ disallowed_methods_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-sky-500 mx-0.5">
count
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-lime-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
d="M18.75 12.75h1.5a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5ZM12 6a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 12 6ZM12 18a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 12 18ZM3.75 6.75h1.5a.75.75 0 1 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5ZM5.25 18.75h-1.5a.75.75 0 0 1 0-1.5h1.5a.75.75 0 0 1 0 1.5ZM3 12a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 3 12ZM9 3.75a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5ZM12.75 12a2.25 2.25 0 1 1 4.5 0 2.25 2.25 0 0 1-4.5 0ZM9 15.75a2.25 2.25 0 1 0 0 4.5 2.25 2.25 0 0 0 0-4.5Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,64 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ modsec_info or "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs." }}
</p>
</div>
</div>
<!-- end info -->
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
MODSECURITY
</p>
<h5 class="mb-1 font-bold dark:text-white/90">{{ modsec_count or "unknown" }}</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5"
>request blocked
</span
>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="scale-75 leading-none text-lg relative fill-red-700 stroke-white"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,214 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- status -->
<div class="col-span-12 grid grid-cols-12 gap-4">
{% if redis_status %}
<div
class="col-span-12 md:col-span-6 2xl:col-span-3 3xl:col-span-2 w-fit h-fit transition hover:scale-102 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="mx-1 flex justify-start items-center">
<h5 class="mb-0 font-bold dark:text-white/90 mr-4">STATUS</h5>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 fill-green-500"
>
<path
fill-rule="evenodd"
d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z"
clip-rule="evenodd"
/>
</svg>
</div>
<p
class="mx-1 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
Active
</p>
</div>
{% else %}
<div
class="col-span-12 md:col-span-6 2xl:col-span-3 3xl:col-span-2 w-fit h-fit transition hover:scale-102 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="mx-1 flex justify-start items-center">
<h5 class="mb-0 font-bold dark:text-white/90 mr-4">STATUS</h5>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 fill-red-500"
>
<path
fill-rule="evenodd"
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z"
clip-rule="evenodd"
/>
</svg>
</div>
<p
class="mx-1 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
Inactive
</p>
</div>
{% endif %}
<!-- end status -->
</div>
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ redis_info or "Redis server configuration when using BunkerWeb in
cluster mode. " }}
</p>
</div>
</div>
<!-- end info -->
<!-- test-->
<div
class="transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">TEST</h5>
<p
class="my-2 transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80 text-center"
>
Use the next button to ping Redis.
</p>
<div class="flex justify-center mt-4">
<button type="button" class="edit-btn text-sm" onclick="ping()">
Ping Redis
</button>
</div>
<hr
class="h-px mx-0 mt-3 mb-2 bg-transparent bg-gradient-to-r from-transparent via-black/40 to-transparent dark:bg-gradient-to-r dark:from-transparent dark:via-white dark:to-transparent"
/>
<div id="response-div" class="flex justify-center items-center">
<div id="no-test" class="flex justify-center items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-gray-600"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-gray-600 text-base uppercase">
UNKNOWN
</p>
</div>
<div
class="hidden flex justify-center items-center"
id="response-success"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-green-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-green-500 text-base uppercase">
SUCCESS
</p>
</div>
<div class="hidden flex justify-center items-center" id="response-failed">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-red-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-red-500 text-base uppercase">
FAILED
</p>
</div>
<div class="hidden flex justify-center items-center" id="response-none">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 stroke-red-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M18.364 18.364A9 9 0 0 0 5.636 5.636m12.728 12.728A9 9 0 0 1 5.636 5.636m12.728 12.728L5.636 5.636"
/>
</svg>
<p class="mb-0 ml-1 font-semibold text-red-500 text-base uppercase">
FAILED
</p>
</div>
</div>
</div>
<!-- end test -->
<script async>
function ping() {
let data = new FormData();
data.set("csrf_token", "{{ csrf_token() }}");
let xhr = new XMLHttpRequest();
xhr.open("POST", "{{ url_for('plugins') }}/bunkernet", true);
xhr.send(data);
xhr.onload = function () {
document.getElementById("no-test").classList.add("hidden");
if (xhr.status == 200) {
document.getElementById("response-failed").classList.remove("hidden");
document.getElementById("response-none").classList.add("hidden");
document.getElementById("response-success").classList.add("hidden");
} else if (xhr.status == 403) {
document
.getElementById("response-success")
.classList.remove("hidden");
document.getElementById("response-none").classList.add("hidden");
document.getElementById("response-failed").classList.add("hidden");
} else {
document.getElementById("response-none").classList.remove("hidden");
document.getElementById("response-success").classList.add("hidden");
document.getElementById("response-failed").classList.add("hidden");
}
};
}
</script>
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,78 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"port" : 4000,
"count" : 400}, {"port" : 4400, "count" : 780}, {"port" : 5000, "count" : 40},
]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ reversescan_info or "Reverse scan is a feature designed to detect
open ports by establishing TCP connections with clients' IP addresses.
Consider adding this feature if you want to detect possible open proxies
or connections from servers." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[500px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
REVERSE SCAN LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[400px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-5 m-0 pb-2 border-b border-gray-400"
>
Port
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-7 m-0 pb-2 border-b border-gray-400"
>
Block count
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-5 m-0 my-1"
>
{{item['port']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-7 m-0 my-1"
>
{{item['count']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,86 @@
{% extends "base.html" %} {% block content %} {% set items = [ {"server_name" :
"www.example.com", "cn" : "Let's encrypt", "expire" : "15/11/2024"},
{"server_name" : "app1.com", "cn" : "Self signed", "expire" : "11/01/2028"},
{"server_name" : "test.2.fr", "cn" : "Default", "expire" : "31/08/2035"} ]%}
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-4 2xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ lets_encrypt_info or "Selfsigned certificates for secure HTTP
requests." }}
</p>
</div>
</div>
<!-- end info -->
{% if items|length != 0 %}
<div
class="col-span-12 md:col-span-8 3xl:col-span-9 w-full xl:max-w-[600px] overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="col-span-12">
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">
SELFSIGNED LIST
</h5>
</div>
<div class="col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
<div class="min-w-[400px] w-full grid grid-cols-12 rounded p-2">
<!-- header-->
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Server name
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
CN
</p>
<p
class="dark:text-gray-300 h-8 text-sm font-bold col-span-4 m-0 pb-2 border-b border-gray-400"
>
Expiry date
</p>
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full">
{% for item in items %}
<li
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5"
>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['server_name']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['cn']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-4 m-0 my-1"
>
{{item['expire']}}
</p>
</li>
{% endfor %}
</ul>
<!-- end list-->
</div>
<!-- end list container-->
</div>
</div>
{% endif %}
</div>
{% endblock %}

View file

@ -0,0 +1 @@
# Spoofing an action file

View file

@ -0,0 +1,236 @@
{% extends "base.html" %} {% block content %}
<div class="col-span-12 grid grid-cols-12 gap-4">
<div class="col-span-12 grid grid-cols-12 gap-4">
<!-- info-->
<div
class="h-fit transition hover:scale-102 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<h5 class="mb-2 font-bold dark:text-white/90">INFO</h5>
<div class="mx-1 flex justify-start items-center my-4">
<p
class="transition duration-300 ease-in-out mb-0 font-sans text-sm leading-normal dark:text-gray-500 dark:opacity-80"
>
{{ whitelist_info or "Allow access based on internal and external
IP/network/rDNS/ASN whitelists." }}
</p>
</div>
</div>
<!-- end info -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
URL
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ whitelist_url_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5">
passed
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-red-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M19.902 4.098a3.75 3.75 0 0 0-5.304 0l-4.5 4.5a3.75 3.75 0 0 0 1.035 6.037.75.75 0 0 1-.646 1.353 5.25 5.25 0 0 1-1.449-8.45l4.5-4.5a5.25 5.25 0 1 1 7.424 7.424l-1.757 1.757a.75.75 0 1 1-1.06-1.06l1.757-1.757a3.75 3.75 0 0 0 0-5.304Zm-7.389 4.267a.75.75 0 0 1 1-.353 5.25 5.25 0 0 1 1.449 8.45l-4.5 4.5a5.25 5.25 0 1 1-7.424-7.424l1.757-1.757a.75.75 0 1 1 1.06 1.06l-1.757 1.757a3.75 3.75 0 1 0 5.304 5.304l4.5-4.5a3.75 3.75 0 0 0-1.035-6.037.75.75 0 0 1-.354-1Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
IP
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ whitelist_ip_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5">
passed
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-lime-600"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
d="M3.53 2.47a.75.75 0 0 0-1.06 1.06l18 18a.75.75 0 1 0 1.06-1.06l-18-18ZM20.25 5.507v11.561L5.853 2.671c.15-.043.306-.075.467-.094a49.255 49.255 0 0 1 11.36 0c1.497.174 2.57 1.46 2.57 2.93ZM3.75 21V6.932l14.063 14.063L12 18.088l-7.165 3.583A.75.75 0 0 1 3.75 21Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
RDNS
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ whitelist_rdns_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5">
passed
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-indigo-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M11.625 16.5a1.875 1.875 0 1 0 0-3.75 1.875 1.875 0 0 0 0 3.75Z"
/>
<path
fill-rule="evenodd"
d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm6 16.5c.66 0 1.277-.19 1.797-.518l1.048 1.048a.75.75 0 0 0 1.06-1.06l-1.047-1.048A3.375 3.375 0 1 0 11.625 18Z"
clip-rule="evenodd"
/>
<path
d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
ASN
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ whitelist_asn_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5">
passed
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-blue-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-[0.6] leading-none text-lg relative fill-white"
>
<path
d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z"
/>
</svg>
</div>
<!-- end icon -->
</div>
<div
class="h-fit dark:brightness-110 max-h-none sm:max-h-28 hover:scale-102 transition col-span-12 md:col-span-6 2xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<!-- text -->
<div>
<p
class="mb-2 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-60"
>
User Agent
</p>
<h5 class="mb-1 font-bold dark:text-white/90">
{{ whitelist_user_agent_count or "unknown" }}
</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-green-500 mx-0.5">
passed
</span>
</p>
</div>
<!-- end text -->
<!-- icon -->
<div
role="img"
class="dark:brightness-90 inline-block w-12 h-12 text-center rounded-circle bg-amber-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="scale-50 leading-none text-lg relative fill-white"
>
<path
fill-rule="evenodd"
d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z"
clip-rule="evenodd"
/>
</svg>
</div>
<!-- end icon -->
</div>
</div>
{% endblock %}

View file

@ -386,7 +386,6 @@ class Database:
for plugin in plugins:
settings = {}
jobs = []
page = False
if "id" not in plugin:
settings = plugin
plugin = {
@ -400,7 +399,7 @@ class Database:
else:
settings = plugin.pop("settings", {})
jobs = plugin.pop("jobs", [])
page = plugin.pop("page", False)
plugin.pop("page", False)
db_plugin = session.query(Plugins).filter_by(id=plugin["id"]).first()
if db_plugin:
@ -549,61 +548,60 @@ class Database:
session.query(Jobs_cache).filter(Jobs_cache.job_name == job["name"]).delete()
session.query(Jobs).filter(Jobs.name == job["name"]).update(updates)
if page:
core_ui_path = Path(sep, "usr", "share", "bunkerweb", "core", plugin["id"], "ui")
path_ui = core_ui_path if core_ui_path.exists() else Path(sep, "etc", "bunkerweb", "plugins", plugin["id"], "ui")
core_ui_path = Path(sep, "usr", "share", "bunkerweb", "core", plugin["id"], "ui")
path_ui = core_ui_path if core_ui_path.exists() else Path(sep, "etc", "bunkerweb", "plugins", plugin["id"], "ui")
if path_ui.exists():
if {"template.html", "actions.py"}.issubset(listdir(str(path_ui))):
db_plugin_page = (
session.query(Plugin_pages)
.with_entities(
Plugin_pages.template_checksum,
Plugin_pages.actions_checksum,
)
.filter_by(plugin_id=plugin["id"])
.first()
if path_ui.exists():
if {"template.html", "actions.py"}.issubset(listdir(str(path_ui))):
db_plugin_page = (
session.query(Plugin_pages)
.with_entities(
Plugin_pages.template_checksum,
Plugin_pages.actions_checksum,
)
template = path_ui.joinpath("template.html").read_bytes()
actions = path_ui.joinpath("actions.py").read_bytes()
template_checksum = sha256(template).hexdigest()
actions_checksum = sha256(actions).hexdigest()
.filter_by(plugin_id=plugin["id"])
.first()
)
template = path_ui.joinpath("template.html").read_bytes()
actions = path_ui.joinpath("actions.py").read_bytes()
template_checksum = sha256(template).hexdigest()
actions_checksum = sha256(actions).hexdigest()
if db_plugin_page:
updates = {}
if template_checksum != db_plugin_page.template_checksum:
updates.update(
{
Plugin_pages.template_file: template,
Plugin_pages.template_checksum: template_checksum,
}
)
if actions_checksum != db_plugin_page.actions_checksum:
updates.update(
{
Plugin_pages.actions_file: actions,
Plugin_pages.actions_checksum: actions_checksum,
}
)
if updates:
self.__logger.warning(f'Page for plugin "{plugin["id"]}" already exists, updating it with the new values')
session.query(Plugin_pages).filter(Plugin_pages.plugin_id == plugin["id"]).update(updates)
continue
if db_plugin:
self.__logger.warning(f'Page for plugin "{plugin["id"]}" does not exist, creating it')
to_put.append(
Plugin_pages(
plugin_id=plugin["id"],
template_file=template,
template_checksum=template_checksum,
actions_file=actions,
actions_checksum=actions_checksum,
if db_plugin_page:
updates = {}
if template_checksum != db_plugin_page.template_checksum:
updates.update(
{
Plugin_pages.template_file: template,
Plugin_pages.template_checksum: template_checksum,
}
)
if actions_checksum != db_plugin_page.actions_checksum:
updates.update(
{
Plugin_pages.actions_file: actions,
Plugin_pages.actions_checksum: actions_checksum,
}
)
if updates:
self.__logger.warning(f'Page for plugin "{plugin["id"]}" already exists, updating it with the new values')
session.query(Plugin_pages).filter(Plugin_pages.plugin_id == plugin["id"]).update(updates)
continue
if db_plugin:
self.__logger.warning(f'Page for plugin "{plugin["id"]}" does not exist, creating it')
to_put.append(
Plugin_pages(
plugin_id=plugin["id"],
template_file=template,
template_checksum=template_checksum,
actions_file=actions,
actions_checksum=actions_checksum,
)
)
try:
session.add_all(to_put)
@ -623,23 +621,42 @@ class Database:
if config:
config.pop("DATABASE_URI", None)
db_services = session.query(Services).with_entities(Services.id, Services.method).all()
db_ids = [service.id for service in db_services]
db_services = session.query(Services).with_entities(Services.id, Services.method, Services.is_draft).all()
db_ids: Dict[str, dict] = {service.id: {"method": service.method, "is_draft": service.is_draft} for service in db_services}
missing_ids = []
services = config.get("SERVER_NAME", [])
if isinstance(services, str):
services = services.split(" ")
if db_services:
missing_ids = [service.id for service in db_services if (service.method == method) and service.id not in services]
missing_ids = [service.id for service in db_services if service.method == method and service.id not in services]
if missing_ids:
# Remove services that are no longer in the list
session.query(Services).filter(Services.id.in_(missing_ids)).delete()
drafts = {service for service in services if config.pop(f"{service}_IS_DRAFT", "no") == "yes"}
db_drafts = {service.id for service in db_services if service.is_draft}
if db_drafts:
missing_drafts = [service.id for service in db_services if service.method == method and service.id not in drafts and service.id not in missing_ids]
if missing_drafts:
# Remove drafts that are no longer in the list
session.query(Services).filter(Services.id.in_(missing_drafts)).update({Services.is_draft: False})
for draft in drafts:
if draft not in db_drafts:
if draft not in db_ids:
to_put.append(Services(id=draft, method=method, is_draft=True))
db_ids[draft] = {"method": method, "is_draft": True}
elif method == db_ids[draft]["method"]:
session.query(Services).filter(Services.id == draft).update({Services.is_draft: True})
if config.get("MULTISITE", "no") == "yes":
global_values = []
for key, value in deepcopy(config).items():
for key, value in config.copy().items():
suffix = 0
original_key = deepcopy(key)
if self.suffix_rx.search(key):
@ -655,8 +672,8 @@ class Database:
continue
if server_name not in db_ids:
to_put.append(Services(id=server_name, method=method))
db_ids.append(server_name)
to_put.append(Services(id=server_name, method=method, is_draft=server_name in drafts))
db_ids[server_name] = {"method": method, "is_draft": server_name in drafts}
key = key.replace(f"{server_name}_", "")
setting = session.query(Settings).with_entities(Settings.default).filter_by(id=key).first()
@ -888,7 +905,7 @@ class Database:
return message
def get_config(self, methods: bool = False) -> Dict[str, Any]:
def get_config(self, methods: bool = False, with_drafts: bool = False) -> Dict[str, Any]:
"""Get the config from the database"""
with self.__db_session() as session:
config = {}
@ -924,8 +941,14 @@ class Database:
is_multisite = config.get("MULTISITE", {"value": "no"})["value"] == "yes" if methods else config.get("MULTISITE", "no") == "yes"
if with_drafts:
services = session.query(Services).with_entities(Services.id, Services.is_draft).all()
else:
services = session.query(Services).with_entities(Services.id, Services.is_draft).filter_by(is_draft=False).all()
if is_multisite:
for service in session.query(Services).with_entities(Services.id).all():
for service in services:
config[f"{service.id}_IS_DRAFT"] = "yes" if service.is_draft else "no"
checked_settings = []
for key, value in deepcopy(config).items():
original_key = key
@ -964,7 +987,7 @@ class Database:
}
)
servers = " ".join(service.id for service in session.query(Services).all())
servers = " ".join(service.id for service in services)
config["SERVER_NAME"] = servers if not methods else {"value": servers, "global": True, "method": "default"}
return config
@ -993,35 +1016,26 @@ class Database:
)
]
def get_services_settings(self, methods: bool = False) -> List[Dict[str, Any]]:
def get_services_settings(self, methods: bool = False, with_drafts: bool = False) -> List[Dict[str, Any]]:
"""Get the services' configs from the database"""
services = []
config = self.get_config(methods=methods)
with self.__db_session() as session:
service_names = [service.id for service in session.query(Services).with_entities(Services.id).all()]
for service in service_names:
service_settings = []
tmp_config = deepcopy(config)
config = self.get_config(methods=methods, with_drafts=with_drafts)
service_names = config["SERVER_NAME"]["value"].split(" ") if methods else config["SERVER_NAME"].split(" ")
for service in service_names:
service_settings = []
tmp_config = deepcopy(config)
for key, value in deepcopy(tmp_config).items():
if key.startswith(f"{service}_"):
setting = key.replace(f"{service}_", "")
service_settings.append(setting)
tmp_config[setting] = tmp_config.pop(key)
elif any(key.startswith(f"{s}_") for s in service_names):
tmp_config.pop(key)
elif key not in service_settings:
tmp_config[key] = (
{
"value": value["value"],
"global": value["global"],
"method": value["method"],
}
if methods
else value
)
for key, value in deepcopy(tmp_config).items():
if key.startswith(f"{service}_"):
setting = key.replace(f"{service}_", "")
service_settings.append(setting)
tmp_config[setting] = tmp_config.pop(key)
elif any(key.startswith(f"{s}_") for s in service_names):
tmp_config.pop(key)
elif key not in service_settings:
tmp_config[key] = {"value": value["value"], "global": value["global"], "method": value["method"]} if methods else value
services.append(tmp_config)
services.append(tmp_config)
return services

View file

@ -109,6 +109,7 @@ class Services(Base):
id = Column(String(64), primary_key=True)
method = Column(METHODS_ENUM, nullable=False)
is_draft = Column(Boolean, default=False, nullable=False)
settings = relationship("Services_settings", back_populates="service", cascade="all")
custom_configs = relationship("Custom_configs", back_populates="service", cascade="all")

View file

@ -3,8 +3,8 @@
"context": "global",
"default": "no",
"help": "Internal use : set to yes when BW is loading.",
"id": "internal-use",
"label": "internal use",
"id": "internal-use-loading",
"label": "internal use loading",
"regex": "^(yes|no)$",
"type": "check"
},
@ -50,7 +50,7 @@
"help": "List of the virtual hosts served by bunkerweb.",
"id": "server-name",
"label": "Server name",
"regex": "^(?! )( ?((?=[^ ]{1,255}( |$))[^ ]+)(?!.* \\2))*$",
"regex": "^((\\S{1,255})(?!.*\\s\\2(\\s|$)))?(\\s(\\S{1,255})(?!.*\\s\\5(\\s|$)))*$",
"type": "text"
},
"WORKER_PROCESSES": {
@ -288,5 +288,14 @@
"label": "Use IPv6",
"regex": "^(yes|no)$",
"type": "check"
},
"IS_DRAFT": {
"context": "multisite",
"default": "no",
"help": "Internal use : set to yes when the service is in draft mode.",
"id": "internal-use-draft",
"label": "internal use draft",
"regex": "^(yes|no)$",
"type": "check"
}
}

View file

@ -15,9 +15,9 @@
},
{
"id": "modsecurity",
"name": "ModSecurity v3.0.11",
"name": "ModSecurity v3.0.12",
"url": "https://github.com/SpiderLabs/ModSecurity.git",
"commit": "bbde9381cbccb49ea73f6194b08b478adc53f3bc",
"commit": "5f44383236b94ef8066529861d0b4d603f9b3bcb",
"post_install": "patch --forward src/deps/src/modsecurity/configure.ac src/deps/misc/modsecurity.patch && rm -rf src/deps/src/modsecurity/others/libinjection"
},
{

View file

@ -45,7 +45,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-11]
os: [macos-12]
compiler: [clang]
configure:
- {label: "with parser generation", opt: "--enable-parser-generation" }

View file

@ -1,3 +1,11 @@
v3.0.12 - 2024-Jan-30
---------------------
- Change REQUEST_FILENAME and REQUEST_BASENAME behavior
[Issue #3048 - @martinhsv, @theMiddleBlue, @theseion, @M4tteoP, @airween]
- Set the minimum security protocol version for SecRemoteRules
[Issue security/code-scanning/2 - @airween]
v3.0.11 - 2023-Dec-06
---------------------

View file

@ -1,16 +1,16 @@
<img src="https://github.com/SpiderLabs/ModSecurity/raw/v3/master/others/modsec.png" width="50%">
<img src="https://github.com/owasp-modsecurity/ModSecurity/raw/v3/master/others/modsec.png" width="50%">
![Quality Assurance](https://github.com/SpiderLabs/ModSecurity/workflows/Quality%20Assurance/badge.svg)
[![Build Status](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=alert_status)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=sqale_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=reliability_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=security_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=vulnerabilities
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
![Quality Assurance](https://github.com/owasp-modsecurity/ModSecurity/workflows/Quality%20Assurance/badge.svg)
[![Build Status](https://sonarcloud.io/api/project_badges/measure?project=owasp-modsecurity_ModSecurity&metric=alert_status)](https://sonarcloud.io/dashboard?id=owasp-modsecurity_ModSecurity)
[![](https://sonarcloud.io/api/project_badges/measure?project=owasp-modsecurity_ModSecurity&metric=sqale_rating
)](https://sonarcloud.io/dashboard?id=owasp-modsecurity_ModSecurity)
[![](https://sonarcloud.io/api/project_badges/measure?project=owasp-modsecurity_ModSecurity&metric=reliability_rating
)](https://sonarcloud.io/dashboard?id=owasp-modsecurity_ModSecurity)
[![](https://sonarcloud.io/api/project_badges/measure?project=owasp-modsecurity_ModSecurity&metric=security_rating
)](https://sonarcloud.io/dashboard?id=owasp-modsecurity_ModSecurity)
[![](https://sonarcloud.io/api/project_badges/measure?project=owasp-modsecurity_ModSecurity&metric=vulnerabilities
)](https://sonarcloud.io/dashboard?id=owasp-modsecurity_ModSecurity)
@ -21,7 +21,7 @@ capability to load/interpret rules written in the ModSecurity SecRules format
and apply them to HTTP content provided by your application via Connectors.
If you are looking for ModSecurity for Apache (aka ModSecurity v2.x), it is still under maintenance and available:
[here](https://github.com/SpiderLabs/ModSecurity/tree/v2/master).
[here](https://github.com/owasp-modsecurity/ModSecurity/tree/v2/master).
### What is the difference between this project and the old ModSecurity (v2.x.x)?
@ -37,7 +37,7 @@ As a result of this goal we have rearchitected Libmodsecurity such that it is no
### It is no longer just a module.
The 'ModSecurity' branch no longer contains the traditional module logic (for Nginx, Apache, and IIS) that has traditionally been packaged all together. Instead, this branch only contains the library portion (libmodsecurity) for this project. This library is consumed by what we have termed 'Connectors' these connectors will interface with your webserver and provide the library with a common format that it understands. Each of these connectors is maintained as a separate GitHub project. For instance, the Nginx connector is supplied by the ModSecurity-nginx project (https://github.com/SpiderLabs/ModSecurity-nginx).
The 'ModSecurity' branch no longer contains the traditional module logic (for Nginx, Apache, and IIS) that has traditionally been packaged all together. Instead, this branch only contains the library portion (libmodsecurity) for this project. This library is consumed by what we have termed 'Connectors' these connectors will interface with your webserver and provide the library with a common format that it understands. Each of these connectors is maintained as a separate GitHub project. For instance, the Nginx connector is supplied by the ModSecurity-nginx project (https://github.com/owasp-modsecurity/ModSecurity-nginx).
Keeping these connectors separated allows each project to have different release cycles, issues and development trees. Additionally, it means that when you install ModSecurity v3 you only get exactly what you need, no extras you won't be using.
@ -67,7 +67,7 @@ $ sudo make install
```
Details on distribution specific builds can be found in our Wiki:
[Compilation Recipes](https://github.com/SpiderLabs/ModSecurity/wiki/Compilation-recipes)
[Compilation Recipes](https://github.com/owasp-modsecurity/ModSecurity/wiki/Compilation-recipes)
### Windows
@ -251,7 +251,7 @@ is one.
### Security issue
Please do not make public any security issue. Contact us at:
security@modsecurity.org reporting the issue. Once the problem is fixed your
modsecurity@owasp.org reporting the issue. Once the problem is fixed your
credit will be given.
## Feature request

View file

@ -6,4 +6,4 @@ The latest versions of both v2.9.x and v3.0.x are supported.
## Reporting a Vulnerability
For information on how to report a security issue, please see https://github.com/SpiderLabs/ModSecurity#security-issue
For information on how to report a security issue, please see https://github.com/owasp-modsecurity/ModSecurity#security-issue

View file

@ -190,7 +190,7 @@ namespace modsecurity {
#define MODSECURITY_MAJOR "3"
#define MODSECURITY_MINOR "0"
#define MODSECURITY_PATCHLEVEL "11"
#define MODSECURITY_PATCHLEVEL "12"
#define MODSECURITY_TAG ""
#define MODSECURITY_TAG_NUM "100"
@ -198,7 +198,7 @@ namespace modsecurity {
MODSECURITY_MINOR "." MODSECURITY_PATCHLEVEL \
MODSECURITY_TAG
#define MODSECURITY_VERSION_NUM 30110100
#define MODSECURITY_VERSION_NUM 30120100
#define MODSECURITY_CHECK_VERSION(a) (MODSECURITY_VERSION_NUM <= a)

View file

@ -463,6 +463,14 @@ int Transaction::processURI(const char *uri, const char *method,
size_t pos_raw_query = uri_s.find("?");
std::string path_info_raw;
if (pos_raw_query == std::string::npos) {
path_info_raw = std::string(uri_s, 0);
} else {
path_info_raw = std::string(uri_s, 0, pos_raw_query);
}
std::string path_info = utils::uri_decode(path_info_raw);
m_uri_decoded = utils::uri_decode(uri_s);
size_t var_size = pos_raw_query;
@ -477,15 +485,8 @@ int Transaction::processURI(const char *uri, const char *method,
m_variableRequestProtocol.set("HTTP/" + std::string(http_version),
m_variableOffset + requestLine.size() + 1);
size_t pos_query = m_uri_decoded.find("?");
if (pos_query != std::string::npos) {
m_uri_no_query_string_decoded = std::unique_ptr<std::string>(
new std::string(m_uri_decoded, 0, pos_query));
} else {
m_uri_no_query_string_decoded = std::unique_ptr<std::string>(
new std::string(m_uri_decoded));
}
m_uri_no_query_string_decoded = std::unique_ptr<std::string>(
new std::string(path_info));
if (pos_raw_query != std::string::npos) {
@ -495,12 +496,7 @@ int Transaction::processURI(const char *uri, const char *method,
+ std::string(method).size() + 1);
}
std::string path_info;
if (pos_query == std::string::npos) {
path_info = std::string(m_uri_decoded, 0);
} else {
path_info = std::string(m_uri_decoded, 0, pos_query);
}
if (var_size == std::string::npos) {
var_size = uri_s.size();
}

View file

@ -87,8 +87,8 @@ bool HttpsClient::download(const std::string &uri) {
headers_chunk = curl_slist_append(headers_chunk, m_key.c_str());
}
/* Make it TLS 1.x only. */
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
/* Make it TLS 1.2 at least. */
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
/* those are the default options, but lets make sure */
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);

View file

@ -2,7 +2,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: PATH_INFO (1/3)",
"title":"Testing Variables :: PATH_INFO (1/4)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -46,7 +46,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: PATH_INFO (2/3)",
"title":"Testing Variables :: PATH_INFO (2/4)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -90,7 +90,7 @@
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: PATH_INFO (3/3)",
"title":"Testing Variables :: PATH_INFO (3/4)",
"client":{
"ip":"200.249.12.31",
"port":123
@ -130,5 +130,49 @@
"SecRuleEngine On",
"SecRule PATH_INFO \"@contains test \" \"id:1,phase:3,pass,t:trim\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing Variables :: PATH_INFO (4/4)",
"client":{
"ip":"200.249.12.31",
"port":123
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"Content-Length":"27",
"Content-Type":"application/x-www-form-urlencoded"
},
"uri":"/one/t%3fo/three?key=value",
"method":"POST",
"body":[
"param1=value1&param2=value2"
]
},
"response":{
"headers":{
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
"Content-Type":"text/html"
},
"body":[
"no need."
]
},
"expected":{
"http_code": 403
},
"rules":[
"SecRuleEngine On",
"SecRule PATH_INFO \"@contains three\" \"id:1,phase:2,deny,status:403,t:trim\""
]
}
]

View file

@ -77,7 +77,7 @@ COPY --chown=root:scheduler src/bw/misc/country.mmdb /var/tmp/bunkerweb/country.
RUN chmod 770 /var/tmp/bunkerweb/asn.mmdb /var/tmp/bunkerweb/country.mmdb
# Fix CVEs
RUN apk add --no-cache "sqlite-libs>=3.41.2-r3"
RUN apk add --no-cache "libcrypto3>=3.1.4-r5" "libssl3>=3.1.4-r5" "sqlite-libs>=3.41.2-r3"
VOLUME /data /etc/nginx

View file

@ -70,7 +70,7 @@ RUN apk add --no-cache bash && \
ln -s /proc/1/fd/2 /var/log/bunkerweb/ui.log
# Fix CVEs
RUN apk add --no-cache "libcrypto3>=3.1.4-r3" "libssl3>=3.1.4-r3" "sqlite-libs>=3.41.2-r3"
RUN apk add --no-cache "libcrypto3>=3.1.4-r5" "libssl3>=3.1.4-r5" "sqlite-libs>=3.41.2-r3"
VOLUME /data /etc/nginx

View file

@ -215,7 +215,7 @@ LOG_RX = re_compile(r"^(?P<date>\d+/\d+/\d+\s\d+:\d+:\d+)\s\[(?P<level>[a-z]+)\]
REVERSE_PROXY_PATH = re_compile(r"^(?P<host>https?://.{1,255}(:((6553[0-5])|(655[0-2]\d)|(65[0-4]\d{2})|(6[0-4]\d{3})|([1-5]\d{4})|([0-5]{0,5})|(\d{1,4})))?)$")
def manage_bunkerweb(method: str, *args, operation: str = "reloads"):
def manage_bunkerweb(method: str, *args, operation: str = "reloads", is_draft: bool = False):
# Do the operation
error = False
if method == "services":
@ -224,27 +224,27 @@ def manage_bunkerweb(method: str, *args, operation: str = "reloads"):
deleted = False
if operation == "new":
operation, error = app.config["CONFIG"].new_service(args[0])
operation, error = app.config["CONFIG"].new_service(args[0], is_draft=is_draft)
elif operation == "edit":
if args[1].split(" ")[0] != args[2].split(" ")[0] and service_custom_confs:
for service_custom_conf in service_custom_confs:
if listdir(service_custom_conf):
move(service_custom_conf, service_custom_conf.replace(f"{sep}{args[1].split(' ')[0]}", f"{sep}{args[2].split(' ')[0]}"))
moved = True
operation, error = app.config["CONFIG"].edit_service(args[1], args[0], check_changes=not moved)
operation, error = app.config["CONFIG"].edit_service(args[1], args[0], check_changes=not is_draft and not moved, is_draft=is_draft)
elif operation == "delete":
for service_custom_conf in glob(join(sep, "etc", "bunkerweb", "configs", "*", args[2].split(" ")[0])):
if listdir(service_custom_conf):
rmtree(service_custom_conf, ignore_errors=True)
deleted = True
operation, error = app.config["CONFIG"].delete_service(args[2], check_changes=not deleted)
operation, error = app.config["CONFIG"].delete_service(args[2], check_changes=not is_draft and not deleted)
if error:
app.config["TO_FLASH"].append({"content": operation, "type": "error"})
else:
app.config["TO_FLASH"].append({"content": operation, "type": "success"})
if moved or deleted:
if not is_draft and (moved or deleted):
changes = ["config", "custom_configs"]
error = app.config["CONFIGFILES"].save_configs(check_changes=False)
if error:
@ -693,17 +693,17 @@ def instances():
def services():
if request.method == "POST":
# Check operation
if "operation" not in request.form or request.form["operation"] not in (
"new",
"edit",
"delete",
):
if "operation" not in request.form or request.form["operation"] not in ("new", "edit", "delete"):
flash("Missing operation parameter on /services.", "error")
return redirect(url_for("loading", next=url_for("services")))
elif "is_draft" not in request.form or request.form["is_draft"] not in ("yes", "no"):
flash("Missing is_draft parameter on /services.", "error")
return redirect(url_for("loading", next=url_for("services")))
# Check variables
variables = deepcopy(request.form.to_dict())
del variables["csrf_token"]
is_draft = variables.pop("is_draft") == "yes"
if "OLD_SERVER_NAME" not in request.form and request.form["operation"] == "edit":
flash("Missing OLD_SERVER_NAME parameter.", "error")
@ -717,7 +717,7 @@ def services():
del variables["OLD_SERVER_NAME"]
# Edit check fields and remove already existing ones
config = app.config["CONFIG"].get_config(methods=False)
config = app.config["CONFIG"].get_config(methods=False, with_drafts=True)
server_name = variables["SERVER_NAME"].split(" ")[0]
for variable, value in deepcopy(variables).items():
if variable.endswith("SCHEMA"):
@ -732,11 +732,8 @@ def services():
if variable in variables and variable != "SERVER_NAME" and value == config.get(f"{server_name}_{variable}" if request.form["operation"] == "edit" else variable, None):
del variables[variable]
if request.form["operation"] == "edit" and len(variables) == 1 and "SERVER_NAME" in variables and variables["SERVER_NAME"] == request.form.get("OLD_SERVER_NAME", ""):
flash(
"The service was not edited because no values were changed.",
"error",
)
if (config.get(f"{server_name}_IS_DRAFT", "no") == "yes") == is_draft and request.form["operation"] == "edit" and len(variables) == 1 and "SERVER_NAME" in variables and variables["SERVER_NAME"] == request.form.get("OLD_SERVER_NAME", ""):
flash("The service was not edited because no values were changed.", "error")
return redirect(url_for("loading", next=url_for("services")))
elif request.form["operation"] == "new" and not variables:
flash("The service was not created because all values had the default value.", "error")
@ -767,22 +764,22 @@ def services():
target=manage_bunkerweb,
name="Reloading instances",
args=("services", variables, request.form.get("OLD_SERVER_NAME", ""), variables.get("SERVER_NAME", "")),
kwargs={"operation": request.form["operation"]},
kwargs={"operation": request.form["operation"], "is_draft": is_draft},
).start()
message = ""
if request.form["operation"] == "new":
message = f"Creating service {variables.get('SERVER_NAME', '').split(' ')[0]}"
message = f"Creating {'draft ' if is_draft else ''}service {variables.get('SERVER_NAME', '').split(' ')[0]}"
elif request.form["operation"] == "edit":
message = f"Saving configuration for service {request.form.get('OLD_SERVER_NAME', '').split(' ')[0]}"
message = f"Saving configuration for {'draft ' if is_draft else ''}service {request.form.get('OLD_SERVER_NAME', '').split(' ')[0]}"
elif request.form["operation"] == "delete":
message = f"Deleting service {request.form.get('SERVER_NAME', '').split(' ')[0]}"
message = f"Deleting {'draft ' if is_draft else ''}service {request.form.get('SERVER_NAME', '').split(' ')[0]}"
return redirect(url_for("loading", next=url_for("services"), message=message))
# Display services
services = app.config["CONFIG"].get_services()
services = app.config["CONFIG"].get_services(with_drafts=True)
return render_template(
"services.html",
services=[
@ -792,6 +789,7 @@ def services():
"full_value": service["SERVER_NAME"]["value"],
"method": service["SERVER_NAME"]["method"],
},
"IS_DRAFT": service.pop("IS_DRAFT", "no"),
"USE_REVERSE_PROXY": service["USE_REVERSE_PROXY"],
"SERVE_FILES": service["SERVE_FILES"],
"REMOTE_PHP": service["REMOTE_PHP"],

View file

@ -36,6 +36,9 @@ class Config:
plugins_settings = self.get_plugins_settings()
for service in services_conf:
server_name = service["SERVER_NAME"].split(" ")[0]
if not server_name:
continue
for k in service:
key_without_server_name = k.replace(f"{server_name}_", "")
if plugins_settings[key_without_server_name]["context"] != "global" if key_without_server_name in plugins_settings else True:
@ -98,7 +101,7 @@ class Config:
def get_settings(self) -> dict:
return self.__settings
def get_config(self, methods: bool = True) -> dict:
def get_config(self, methods: bool = True, with_drafts: bool = False) -> dict:
"""Get the nginx variables env file and returns it as a dict
Returns
@ -106,9 +109,9 @@ class Config:
dict
The nginx variables env file as a dict
"""
return self.__db.get_config(methods=methods)
return self.__db.get_config(methods=methods, with_drafts=with_drafts)
def get_services(self, methods: bool = True) -> list[dict]:
def get_services(self, methods: bool = True, with_drafts: bool = False) -> list[dict]:
"""Get nginx's services
Returns
@ -116,7 +119,7 @@ class Config:
list
The services
"""
return self.__db.get_services_settings(methods=methods)
return self.__db.get_services_settings(methods=methods, with_drafts=with_drafts)
def check_variables(self, variables: dict, _global: bool = False) -> int:
"""Testify that the variables passed are valid
@ -163,7 +166,7 @@ class Config:
def reload_config(self) -> None:
self.__gen_conf(self.get_config(methods=False), self.get_services(methods=False))
def new_service(self, variables: dict) -> Tuple[str, int]:
def new_service(self, variables: dict, is_draft: bool = False) -> Tuple[str, int]:
"""Creates a new service from the given variables
Parameters
@ -181,23 +184,17 @@ class Config:
Exception
raise this if the service already exists
"""
services = self.get_services(methods=False)
services = self.get_services(methods=False, with_drafts=True)
server_name_splitted = variables["SERVER_NAME"].split(" ")
for service in services:
if service["SERVER_NAME"] == variables["SERVER_NAME"] or service["SERVER_NAME"] in server_name_splitted:
return (
f"Service {service['SERVER_NAME'].split(' ')[0]} already exists.",
1,
)
return f"Service {service['SERVER_NAME'].split(' ')[0]} already exists.", 1
services.append(variables)
self.__gen_conf(self.get_config(methods=False), services)
return (
f"Configuration for {variables['SERVER_NAME'].split(' ')[0]} has been generated.",
0,
)
services.append(variables | {"IS_DRAFT": "yes" if is_draft else "no"})
self.__gen_conf(self.get_config(methods=False), services, check_changes=not is_draft)
return f"Configuration for {variables['SERVER_NAME'].split(' ')[0]} has been generated.", 0
def edit_service(self, old_server_name: str, variables: dict, *, check_changes: bool = True) -> Tuple[str, int]:
def edit_service(self, old_server_name: str, variables: dict, *, check_changes: bool = True, is_draft: bool = False) -> Tuple[str, int]:
"""Edits a service
Parameters
@ -212,22 +209,19 @@ class Config:
str
the confirmation message
"""
services = self.get_services(methods=False)
services = self.get_services(methods=False, with_drafts=True)
changed_server_name = old_server_name != variables["SERVER_NAME"]
server_name_splitted = variables["SERVER_NAME"].split(" ")
old_server_name_splitted = old_server_name.split(" ")
for i, service in enumerate(deepcopy(services)):
if service["SERVER_NAME"] == variables["SERVER_NAME"] or service["SERVER_NAME"] in server_name_splitted:
if changed_server_name and service["SERVER_NAME"].split(" ")[0] != old_server_name_splitted[0]:
return (
f"Service {service['SERVER_NAME'].split(' ')[0]} already exists.",
1,
)
return f"Service {service['SERVER_NAME'].split(' ')[0]} already exists.", 1
services.pop(i)
elif changed_server_name and (service["SERVER_NAME"] == old_server_name or service["SERVER_NAME"] in old_server_name_splitted):
services.pop(i)
services.append(variables)
services.append(variables | {"IS_DRAFT": "yes" if is_draft else "no"})
config = self.get_config(methods=False)
if changed_server_name and server_name_splitted[0] != old_server_name_splitted[0]:
@ -236,10 +230,7 @@ class Config:
config.pop(k)
self.__gen_conf(config, services, check_changes=check_changes)
return (
f"Configuration for {old_server_name_splitted[0]} has been edited.",
0,
)
return f"Configuration for {old_server_name_splitted[0]} has been edited.", 0
def edit_global_conf(self, variables: dict) -> str:
"""Edits the global conf
@ -277,7 +268,7 @@ class Config:
"""
service_name = service_name.split(" ")[0]
full_env = self.get_config(methods=False)
services = self.get_services(methods=False)
services = self.get_services(methods=False, with_drafts=True)
new_services = []
found = False

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -21,7 +21,7 @@ class Filter {
setTimeout(() => {
const value = document
.querySelector(
`[data-${this.prefix}-setting-select-text="reason"]`
`[data-${this.prefix}-setting-select-text="reason"]`,
)
.textContent.trim();
@ -159,7 +159,7 @@ class Dropdown {
const btn = e.target.closest("button");
const btnValue = btn.getAttribute("value");
const btnSetting = btn.getAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`
`data-${this.prefix}-setting-select-dropdown-btn`,
);
//stop if same value to avoid new fetching
const isSameVal = this.isSameValue(btnSetting, btnValue);
@ -185,7 +185,7 @@ class Dropdown {
closeAllDrop() {
const drops = document.querySelectorAll(
`[data-${this.prefix}-setting-select-dropdown]`
`[data-${this.prefix}-setting-select-dropdown]`,
);
drops.forEach((drop) => {
drop.classList.add("hidden");
@ -193,8 +193,8 @@ class Dropdown {
document
.querySelector(
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
`data-${this.prefix}-setting-select-dropdown`
)}"]`
`data-${this.prefix}-setting-select-dropdown`,
)}"]`,
)
.classList.remove("rotate-180");
});
@ -202,7 +202,7 @@ class Dropdown {
isSameValue(btnSetting, value) {
const selectCustom = document.querySelector(
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`,
);
const currVal = selectCustom.textContent;
return currVal === value ? true : false;
@ -210,30 +210,30 @@ class Dropdown {
setSelectNewValue(btnSetting, value) {
const selectCustom = document.querySelector(
`[data-${this.prefix}-setting-select="${btnSetting}"]`
`[data-${this.prefix}-setting-select="${btnSetting}"]`,
);
selectCustom.querySelector(
`[data-${this.prefix}-setting-select-text]`
`[data-${this.prefix}-setting-select-text]`,
).textContent = value;
}
hideDropdown(btnSetting) {
//hide dropdown
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
);
dropdownEl.classList.add("hidden");
dropdownEl.classList.remove("flex");
//svg effect
const dropdownChevron = document.querySelector(
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`,
);
dropdownChevron.classList.remove("rotate-180");
}
changeDropBtnStyle(btnSetting, selectedBtn) {
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
);
//reset dropdown btns
const btnEls = dropdownEl.querySelectorAll("button");
@ -243,7 +243,7 @@ class Dropdown {
"bg-primary",
"dark:bg-primary",
"text-gray-300",
"text-gray-300"
"text-gray-300",
);
btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700");
});
@ -251,7 +251,7 @@ class Dropdown {
selectedBtn.classList.remove(
"bg-white",
"dark:bg-slate-700",
"text-gray-700"
"text-gray-700",
);
selectedBtn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
}
@ -262,10 +262,10 @@ class Dropdown {
.getAttribute(`data-${this.prefix}-setting-select`);
//toggle dropdown
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`,
);
const dropdownChevron = document.querySelector(
`svg[data-${this.prefix}-setting-select="${attribute}"]`
`svg[data-${this.prefix}-setting-select="${attribute}"]`,
);
dropdownEl.classList.toggle("hidden");
dropdownEl.classList.toggle("flex");
@ -318,7 +318,7 @@ class Unban {
setTimeout(() => {
// Check if at least one item is selected
const selected = this.listEl.querySelectorAll(
`input[data-checked="true"]`
`input[data-checked="true"]`,
);
// Case true, enable unban button
@ -340,7 +340,7 @@ class Unban {
if (this.unbanBtn.hasAttribute("disabled")) return;
// Get all selected items
const selected = this.listEl.querySelectorAll(
`input[data-checked="true"]`
`input[data-checked="true"]`,
);
const getDatas = [];
selected.forEach((el) => {
@ -366,7 +366,7 @@ class AddBanModal {
this.listEl = document.querySelector(`[data-bans-add-ban-list]`);
this.submitBtn = document.querySelector(`button[data-bans-modal-submit]`);
this.removeAllFieldBtn = document.querySelector(
"button[data-add-ban-delete-all-item]"
"button[data-add-ban-delete-all-item]",
);
this.formEl = document.querySelector("form[data-ban-add-form]");
this.itemCount = 0;
@ -561,7 +561,10 @@ class AddBanModal {
setDatepicker(id) {
const defaultDate = +(Date.now() + 3600000 * 24);
const inpEl = document.querySelector(`input#ban-end-${id}`);
inpEl.setAttribute("data-timestamp", defaultDate.toString().substring(0, 10));
inpEl.setAttribute(
"data-timestamp",
defaultDate.toString().substring(0, 10),
);
// instantiate datepicker
const dateOptions = {
@ -579,7 +582,10 @@ class AddBanModal {
// Case pick is before current date
if (pickStamp < nowStamp) {
inpEl.setAttribute("data-timestamp", defaultDate.toString().substring(0, 10));
inpEl.setAttribute(
"data-timestamp",
defaultDate.toString().substring(0, 10),
);
return instance.setDate(defaultDate);
}

View file

@ -26,25 +26,53 @@ class ServiceModal {
);
//container
this.container = document.querySelector("main");
this.currAction = "";
this.currMethod = "";
this.init();
}
//store default config data on DOM
//to update modal data on new button click
getActionAndServName(target) {
getActionData(target) {
const action = target
.closest("button")
.getAttribute("data-services-action");
const serviceName = target
.closest("button")
.getAttribute("data-services-name");
const isDraft =
target
.closest("[data-services-service]")
.querySelector("[data-is-draft]")
.getAttribute("data-value") || "no";
return [action, serviceName];
const method =
target
.closest("[data-services-service]")
.querySelector("[data-service-method]")
.getAttribute("data-value") || "no";
this.currMethod = method;
return [action, serviceName, isDraft, method];
}
init() {
this.modal.addEventListener("click", (e) => {
// update draft mode
try {
if (e.target.closest("button").hasAttribute("data-toggle-draft-btn")) {
// Get current state
const currModeIsDraft = e.target
.querySelector('[data-toggle-draft="true"]')
.classList.contains("hidden")
? true
: false;
this.setIsDraft(currModeIsDraft, this.currMethod);
}
} catch (e) {}
//close
try {
if (
@ -63,12 +91,21 @@ class ServiceModal {
"edit"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
);
const oldServName = e.target
.closest("[data-services-service]")
.querySelector("[data-old-service-name]")
.getAttribute("data-value");
this.setForm(action, serviceName, oldServName, this.formNewEdit);
this.setForm(
action,
serviceName,
oldServName,
this.formNewEdit,
isDraft,
method
);
//get service data and parse it
//multiple type logic is launch at same time on relate class
const servicesSettings = e.target
@ -90,8 +127,17 @@ class ServiceModal {
"clone"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
this.setForm(action, serviceName, serviceName, this.formNewEdit);
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
);
this.setForm(
action,
serviceName,
serviceName,
this.formNewEdit,
isDraft,
method
);
//set default value with method default
//get service data and parse it
//multiple type logic is launch at same time on relate class
@ -100,7 +146,7 @@ class ServiceModal {
.querySelector("[data-services-settings]")
.getAttribute("data-value");
const obj = JSON.parse(servicesSettings);
this.updateModalData(obj, true);
this.updateModalData(obj, true, true);
// server name is unset
const inpServName = document.querySelector("input#SERVER_NAME");
inpServName.getAttribute("value", "");
@ -121,8 +167,17 @@ class ServiceModal {
"new"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
this.setForm(action, serviceName, serviceName, this.formNewEdit);
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
);
this.setForm(
action,
serviceName,
serviceName,
this.formNewEdit,
isDraft,
method
);
//set default value with method default
this.setSettingsDefault();
//server name is unset
@ -144,8 +199,17 @@ class ServiceModal {
"delete"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
this.setForm(action, serviceName, serviceName, this.formDelete);
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
);
this.setForm(
action,
serviceName,
serviceName,
this.formDelete,
isDraft,
method
);
//show modal
this.openModal();
}
@ -178,6 +242,7 @@ class ServiceModal {
if (
inpName === "csrf_token" ||
inpName === "OLD_SERVER_NAME" ||
inpName === "is_draft" ||
inpName === "operation" ||
inpName === "settings-filter"
)
@ -248,9 +313,46 @@ class ServiceModal {
}
}
setForm(action, serviceName, oldServName, formEl) {
setIsDraft(isDraft, method) {
console.log(isDraft, method);
const draftVal = isDraft ? "yes" : "no";
document.querySelectorAll('input[name="is_draft"]').forEach((inp) => {
inp.setAttribute("value", draftVal);
inp.value = draftVal;
});
console.log("f");
//Update draft button
const btn = document.querySelector("button[data-toggle-draft-btn]");
if (
(!["ui", "default"].includes(method) && this.currAction !== "clone") ||
this.currAction === "delete"
) {
return btn.classList.add("hidden");
}
btn.classList.remove("hidden");
const showEl = isDraft ? "true" : "false";
btn.querySelectorAll("[data-toggle-draft]").forEach((item) => {
if (item.getAttribute("data-toggle-draft") === showEl)
item.classList.remove("hidden");
if (item.getAttribute("data-toggle-draft") !== showEl)
item.classList.add("hidden");
});
}
setForm(action, serviceName, oldServName, formEl, isDraft, method) {
this.currAction = action;
this.setIsDraft(isDraft === "yes" ? true : false, method);
this.modalTitle.textContent = `${action} ${serviceName}`;
const operation = action === "clone" ? "new" : action;
formEl.setAttribute("id", `form-${operation}-${serviceName}`);
const opeInp = formEl.querySelector(`input[name="operation"]`);
opeInp.setAttribute("value", operation);
@ -326,12 +428,12 @@ class ServiceModal {
this.modalTabsHeader.classList.remove("hidden");
}
updateModalData(settings, forceEnabled = false) {
updateModalData(settings, forceEnabled = false, setMethodUI = false) {
//use this to select inputEl and change value
for (const [key, data] of Object.entries(settings)) {
//change format to match id
const value = data["value"];
const method = data["method"];
const method = setMethodUI ? "ui" : data["method"];
const global = data["global"];
try {
const inps = this.modal.querySelectorAll(`[name='${key}']`);
@ -342,6 +444,7 @@ class ServiceModal {
if (
inpName === "csrf_token" ||
inpName === "OLD_SERVER_NAME" ||
inpName === "is_draft" ||
inpName === "operation" ||
inpName === "settings-filter"
)
@ -461,7 +564,14 @@ class Multiple {
const multipleSettings = this.getMultiplesOnly(obj);
const sortMultiples =
this.sortMultipleByContainerAndSuffixe(multipleSettings);
this.setMultipleToDOM(sortMultiples);
// Need to set method as ui if clone
const isClone =
e.target.closest("button").getAttribute("data-services-action") ===
"clone"
? true
: false;
this.setMultipleToDOM(sortMultiples, isClone);
}
} catch (err) {}
//new service button
@ -664,7 +774,7 @@ class Multiple {
}
//put multiple on the right plugin, on schema container
setMultipleToDOM(sortMultObj) {
setMultipleToDOM(sortMultObj, setMethodUI = false) {
//we loop on each multiple that contains values to render to DOM
for (const [schemaCtnrName, multGroupBySuffix] of Object.entries(
sortMultObj
@ -692,7 +802,7 @@ class Multiple {
//replace input info and disabled state
this.setSetting(
data["value"],
data["method"],
setMethodUI ? "ui" : data["method"],
data["global"],
settingContainer
);
@ -769,6 +879,7 @@ class Multiple {
if (
inpName === "csrf_token" ||
inpName === "OLD_SERVER_NAME" ||
inpName === "is_draft" ||
inpName === "operation" ||
inpName === "settings-filter"
)

View file

@ -5,6 +5,7 @@ module.exports = {
"./templates/*.{html,js}",
"./static/js/*.js",
"./static/js/utils/*.js",
"../common/core/***/**/*.{html,js}",
],
presets: [],

View file

@ -14,6 +14,7 @@
<title>BunkerWeb UI</title>
<link rel="icon" type="image/x-icon" href="images/favicon.ico" />
<!-- tailwind style -->
<link rel="stylesheet" type="text/css" href="./css/plugins.css" />
<link rel="stylesheet" type="text/css" href="./css/dashboard.css" />
<script type="module" src="./js/global.js"></script>

View file

@ -1,4 +1,4 @@
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip()
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', ' ').replace('-', ' ')
%}
<!-- header -->

View file

@ -213,7 +213,7 @@ include "plugins_modal.html" %}
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">LIST</h5>
<div data-{{current_endpoint}}-list class="grid grid-cols-12 gap-3">
{% for plugin in plugins %} {% if plugin['external'] %}
{% for plugin in plugins %}
<div
data-{{current_endpoint}}-external="{% if plugin['external'] %} external {% else %} internal {% endif %}"
class="py-3 min-h-12 relative col-span-12 sm:col-span-6 2xl:col-span-4 3xl:col-span-3 p-1 flex justify-between items-center transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800"
@ -228,7 +228,7 @@ include "plugins_modal.html" %}
{% if plugin['page']%}
<a
aria-label="plugin page link"
class="hover:-translate-y-px"
class="hover:-translate-y-px mx-1"
href="{{request.url_root}}plugins?plugin_id={{plugin['id']}}"
>
<svg
@ -242,6 +242,7 @@ include "plugins_modal.html" %}
</svg>
</a>
{%endif%}
{% if plugin['external'] %}
<button
data-{{current_endpoint}}-action="delete"
name="{{plugin['id']}}"
@ -258,21 +259,10 @@ include "plugins_modal.html" %}
/>
</svg>
</button>
{%endif%}
</div>
</div>
{% else %}
<div
data-{{current_endpoint}}-external="{% if plugin['external'] %} external {%else%} internal {%endif%}"
class="py-3 min-h-12 relative col-span-12 sm:col-span-6 2xl:col-span-4 3xl:col-span-3 p-1 flex justify-between items-center transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800"
>
<p
data-{{current_endpoint}}-content
class="ml-3 mr-2 break-words mb-0 mb-0 transition duration-300 ease-in-out dark:opacity-90 text-left text-sm md:text-base text-slate-700 dark:text-gray-200"
>
{{plugin['name']}}
</p>
</div>
{% endif %} {% endfor %}
{% endfor %}
</div>
</div>
{% endblock %}

View file

@ -50,7 +50,7 @@
</div>
<!-- action button -->
<div class="w-full justify-center flex mt-10">
<button
<button
data-plugins-modal-close
class="close-btn mb-4 mr-3 text-base"
>

View file

@ -1,8 +1,10 @@
{% extends "base.html" %} {% block content %}
<!-- actions -->
<div
<div data-services-service
class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border"
>
<div data-is-draft class="hidden" data-value="no"></div>
<div data-service-method class="hidden" data-value="ui"></div>
<button
data-services-action="new"
data-services-name="service"
@ -32,14 +34,33 @@
{% else %}{% for services_batched in services|batch(3) %} {% for service in
services_batched %} {% set id_server_name =
service["SERVER_NAME"]['value'].replace(".", "-") %}
<div data-services-service
<div data-services-service="{{ service["SERVER_NAME"]['value'] }}"
class="my-2 dark:brightness-110 overflow-hidden hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 p-4 w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div data-services-settings class="hidden" data-value="{{service['settings']}}"></div>
<div data-old-service-name class="hidden" data-value="{{service['SERVER_NAME']['full_value']}}"></div>
<h5 class="transition duration-300 ease-in-out text-center sm:text-left mb-1 font-bold dark:text-white/90">
{{ service["SERVER_NAME"]['value'] }}
</h5>
<div data-is-draft class="hidden" data-value="{% if service.get('IS_DRAFT', "no") == "yes" %}yes{%else%}no{%endif%}"></div>
<div data-service-method class="hidden" data-value="{{service["SERVER_NAME"]['method']}}"></div>
<div class="flex justify-between items-start">
<h5 class="transition duration-300 ease-in-out text-center sm:text-left mb-1 font-bold dark:text-white/90">
{{ service["SERVER_NAME"]['value'] }}
</h5>
{% if service.get('IS_DRAFT', "no") == "yes" and service["SERVER_NAME"]['method'] in ["ui", "default"] %}
<button class="group relative">
<p class="dark:text-gray-300 -z-10 opacity-0 group-hover:z-10 group-hover:opacity-100 transition fixed bg-white dark:bg-slate-800 rounded right-12 px-1 py-0.5">Draft</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6 fill-gray-700 dark:fill-gray-300 cursor-pointer-none">
<path fill-rule="evenodd" d="M10.5 3.798v5.02a3 3 0 0 1-.879 2.121l-2.377 2.377a9.845 9.845 0 0 1 5.091 1.013 8.315 8.315 0 0 0 5.713.636l.285-.071-3.954-3.955a3 3 0 0 1-.879-2.121v-5.02a23.614 23.614 0 0 0-3 0Zm4.5.138a.75.75 0 0 0 .093-1.495A24.837 24.837 0 0 0 12 2.25a25.048 25.048 0 0 0-3.093.191A.75.75 0 0 0 9 3.936v4.882a1.5 1.5 0 0 1-.44 1.06l-6.293 6.294c-1.62 1.621-.903 4.475 1.471 4.88 2.686.46 5.447.698 8.262.698 2.816 0 5.576-.239 8.262-.697 2.373-.406 3.092-3.26 1.47-4.881L15.44 9.879A1.5 1.5 0 0 1 15 8.818V3.936Z" clip-rule="evenodd" />
</svg>
</button>
{% else %}
<button class="group relative">
<p class="dark:text-gray-300 -z-10 opacity-0 group-hover:z-10 group-hover:opacity-100 transition fixed bg-white dark:bg-slate-800 rounded right-12 px-1 py-0.5">Online</p>
<svg data-toggle-draft="false" data-toggle-draft="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6 fill-gray-700 dark:fill-gray-300 cursor-pointer-none">
<path d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z" />
</svg>
</button>
{% endif %}
</div>
<h6 class="text-center sm:text-left mb-2 font-semibold text-gray-600 dark:text-white/80">{{ service["SERVER_NAME"]['method'] }}</h5>
<!-- detail list -->
@ -366,10 +387,11 @@
class="dark:brightness-90 z-20 mx-1 bg-emerald-500 hover:bg-emerald-500/80 focus:bg-emerald-500/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md"
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 fill-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0 0 13.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 0 1-.75.75H9a.75.75 0 0 1-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 0 1 1.927-.184" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6 fill-white">
<path fill-rule="evenodd" d="M17.663 3.118c.225.015.45.032.673.05C19.876 3.298 21 4.604 21 6.109v9.642a3 3 0 0 1-3 3V16.5c0-5.922-4.576-10.775-10.384-11.217.324-1.132 1.3-2.01 2.548-2.114.224-.019.448-.036.673-.051A3 3 0 0 1 13.5 1.5H15a3 3 0 0 1 2.663 1.618ZM12 4.5A1.5 1.5 0 0 1 13.5 3H15a1.5 1.5 0 0 1 1.5 1.5H12Z" clip-rule="evenodd" />
<path d="M3 8.625c0-1.036.84-1.875 1.875-1.875h.375A3.75 3.75 0 0 1 9 10.5v1.875c0 1.036.84 1.875 1.875 1.875h1.875A3.75 3.75 0 0 1 16.5 18v2.625c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625v-12Z" />
<path d="M10.5 10.5a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963 5.23 5.23 0 0 0-3.434-1.279h-1.875a.375.375 0 0 1-.375-.375V10.5Z" />
</svg>
</button>

View file

@ -9,12 +9,24 @@
class="overflow-y-auto mx-0 sm:mx-6 lg:mx-8 my-3 px-4 pt-4 pb-8 w-full sm:min-w-[500px] h-[90vh] flex flex-col break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
>
<div class="w-full flex justify-between mb-2">
<p
data-services-modal-title
class="transition duration-300 ease-in-out dark:opacity-90 dark:text-gray-200 mb-2 font-sans font-semibold leading-normal uppercase text-md"
>
SERVICE MODAL
</p>
<div class="flex justify-start items-center">
<p
data-services-modal-title
class="transition duration-300 ease-in-out dark:opacity-90 dark:text-gray-200 mb-1 font-sans font-semibold leading-normal uppercase text-md"
>
SERVICE MODAL
</p>
<button data-toggle-draft-btn class="transition hover:brightness-75 dark:hover:brightness-110 ml-4 flex items-center border border-gray-700 dark:border-gray-300 rounded py-1 px-2">
<p data-toggle-draft="true" class="hidden dark:text-gray-300 mb-0 mr-2 pointer-events-none">Draft</p>
<p data-toggle-draft="false" class="hidden dark:text-gray-300 mb-0 mr-2 pointer-events-none">Online</p>
<svg data-toggle-draft="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="hidden w-5 h-5 fill-gray-700 dark:fill-gray-300 pointer-events-none">
<path fill-rule="evenodd" d="M10.5 3.798v5.02a3 3 0 0 1-.879 2.121l-2.377 2.377a9.845 9.845 0 0 1 5.091 1.013 8.315 8.315 0 0 0 5.713.636l.285-.071-3.954-3.955a3 3 0 0 1-.879-2.121v-5.02a23.614 23.614 0 0 0-3 0Zm4.5.138a.75.75 0 0 0 .093-1.495A24.837 24.837 0 0 0 12 2.25a25.048 25.048 0 0 0-3.093.191A.75.75 0 0 0 9 3.936v4.882a1.5 1.5 0 0 1-.44 1.06l-6.293 6.294c-1.62 1.621-.903 4.475 1.471 4.88 2.686.46 5.447.698 8.262.698 2.816 0 5.576-.239 8.262-.697 2.373-.406 3.092-3.26 1.47-4.881L15.44 9.879A1.5 1.5 0 0 1 15 8.818V3.936Z" clip-rule="evenodd" />
</svg>
<svg data-toggle-draft="false" data-toggle-draft="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="hidden w-5 h-5 fill-gray-700 dark:fill-gray-300 pointer-events-none">
<path d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z" />
</svg>
</button>
</div>
<button
class="-translate-y-1"
aria-label="close modal"
@ -66,6 +78,7 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" id="operation" value="new" name="operation" />
<input type="hidden" value="new" name="OLD_SERVER_NAME" />
<input type="hidden" value="no" name="is_draft" />
{% include "settings_plugins.html" %}
@ -94,6 +107,7 @@
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" value="delete" name="operation" />
<input type="hidden" value="no" name="is_draft" />
<input type="hidden" value="" name="SERVER_NAME" />
<div class="flex justify-center">

View file

@ -3,6 +3,7 @@
{% set global_config = config["CONFIG"].get_config() %}
{% set plugins = config["CONFIG"].get_plugins() %}
<!-- plugin item -->
{% for plugin in plugins %}
<div
@ -12,11 +13,31 @@ data-plugin-item="{{plugin['id']}}"
>
<!-- title and desc -->
<div class="col-span-12" data-setting-header>
<h5
class="transition duration-300 ease-in-out ml-2 font-bold text-md uppercase dark:text-white/90 mb-0"
>
{{plugin['name']}} <span>{{plugin['version']}}</span>
</h5>
<div class="flex justify-start items-center">
<h5
class="transition duration-300 ease-in-out ml-2 font-bold text-md uppercase dark:text-white/90 mb-0"
>
{{plugin['name']}} <span>{{plugin['version']}}</span>
</h5>
{% if plugin['page']%}
<a
target="_blank"
aria-label="plugin page link"
class="hover:-translate-y-px mx-2"
href="{{request.url_root}}plugins?plugin_id={{plugin['id']}}"
>
<svg
class="h-5 w-5 fill-sky-500 dark dark:brightness-90"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path
d="M288 32c-17.7 0-32 14.3-32 32s14.3 32 32 32h50.7L169.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L384 141.3V192c0 17.7 14.3 32 32 32s32-14.3 32-32V64c0-17.7-14.3-32-32-32H288zM80 64C35.8 64 0 99.8 0 144V400c0 44.2 35.8 80 80 80H336c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32v80c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V144c0-8.8 7.2-16 16-16h80c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z"
></path>
</svg>
</a>
{%endif%}
</div>
<div
class="transition duration-300 ease-in-out dark:opacity-90 ml-2 text-sm mb-2 dark:text-gray-400"
>
@ -26,9 +47,10 @@ data-plugin-item="{{plugin['id']}}"
<!-- end title and desc -->
<div data-plugin-settings class="w-full grid grid-cols-12">
<!-- plugin settings not multiple -->
{% for setting, value in plugin["settings"].items() %}{% if setting != "IS_LOADING" and current_endpoint
== "global-config" and value['context'] == "global" and not value['multiple'] or current_endpoint ==
{% for setting, value in plugin["settings"].items() %}{% if setting not in ["IS_LOADING", "IS_DRAFT"] and current_endpoint
== "global-config" and value['context'] == "global" and not value['multiple'] or setting != "IS_DRAFT" and current_endpoint ==
"services" and value['context'] == "multisite" and not value['multiple'] %}
<div data-setting-container
class="mx-0 sm:mx-4 my-2 col-span-12 md:mx-6 md:my-3 md:col-span-6 2xl:mx-6 2xl:my-3 2xl:col-span-4"
id="form-edit-{{current_endpoint}}-{{ value["id"] }}">

View file

@ -2,11 +2,8 @@ version: "3.5"
services:
bw:
# image: bunkerity/bunkerweb:1.5.6
# pull_policy: never
build:
context: ../../..
dockerfile: src/bw/Dockerfile
image: bunkerity/bunkerweb:1.5.6
pull_policy: never
labels:
- "bunkerweb.INSTANCE=yes"
volumes:
@ -40,11 +37,8 @@ services:
ipv4_address: 192.168.0.2
bw-scheduler:
# image: bunkerity/bunkerweb-scheduler:1.5.6
# pull_policy: never
build:
context: ../../..
dockerfile: src/scheduler/Dockerfile
image: bunkerity/bunkerweb-scheduler:1.5.6
pull_policy: never
depends_on:
- bw
- bw-docker

View file

@ -106,18 +106,6 @@ cleanup_stack () {
if [[ $(sed '20!d' docker-compose.test.yml) = " CUSTOM_CONF_SERVICE_MODSEC_CRS_test_service_conf: 'SecRule REQUEST_FILENAME \"@rx ^/test\" \"id:10001,ctl:ruleRemoveByTag=attack-generic,ctl:ruleRemoveByTag=attack-protocol,nolog\"'" ]] ; then
sed -i '20d' docker-compose.test.yml
fi
if [ $end -eq 0 ] ; then
echo "💾 Removing bw-docker network ..."
docker network rm bw-docker
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "💾 Network removal failed ❌"
exit 1
fi
fi
else
sudo rm -rf /etc/bunkerweb/plugins/*
sudo sed -i 's@MULTISITE=.*$@MULTISITE=no@' /etc/bunkerweb/variables.env
@ -152,6 +140,18 @@ cleanup_stack () {
else
docker compose down -v --remove-orphans
fi
if [[ $end -eq 0 && $exit_code = 1 ]] && [ $manual = 0 ] ; then
echo "💾 Removing bw-docker network ..."
docker network rm bw-docker
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "💾 Network removal failed ❌"
exit 1
fi
fi
else
sudo systemctl stop bunkerweb
sudo truncate -s 0 /var/log/bunkerweb/error.log
@ -476,6 +476,20 @@ do
sed -i 's@bunkerity/bunkerweb:.*$@bunkerity/bunkerweb:'"$older_version"'@' docker-compose.yml
sed -i 's@bunkerity/bunkerweb-scheduler:.*$@bunkerity/bunkerweb-scheduler:'"$older_version"'@' docker-compose.yml
docker pull bunkerity/bunkerweb:"$older_version"
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "💾 Pull for bunkerweb:$older_version failed ❌"
exit 1
fi
docker pull bunkerity/bunkerweb-scheduler:"$older_version"
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "💾 Pull for bunkerweb-scheduler:$older_version failed ❌"
exit 1
fi
starting_stack
waiting_stack

View file

@ -0,0 +1,14 @@
FROM python:3.12.1-alpine3.18@sha256:fb759579d60cfe1f70b110a27be95aaa7cf758d2fa21cf54fffb71c2ba3f8034
WORKDIR /tmp
COPY requirements.txt .
RUN MAKEFLAGS="-j $(nproc)" pip install --no-cache-dir --require-hashes --no-deps -r requirements.txt && \
rm -f requirements.txt
WORKDIR /opt/tests
COPY main.py .
ENTRYPOINT [ "python3", "main.py" ]

View file

@ -0,0 +1,17 @@
version: "3.5"
services:
tests:
build: .
environment:
PYTHONUNBUFFERED: "1"
AUTO_LETS_ENCRYPT: "no"
extra_hosts:
- "www.example.com:192.168.0.2"
networks:
bw-services:
ipv4_address: 192.168.0.3
networks:
bw-services:
external: true

View file

@ -0,0 +1,74 @@
version: "3.5"
services:
bw:
image: bunkerity/bunkerweb:1.5.6
pull_policy: never
labels:
- "bunkerweb.INSTANCE=yes"
volumes:
- ./index.html:/var/www/html/index.html
environment:
SERVER_NAME: "www.example.com"
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24 192.168.0.3"
HTTP_PORT: "80"
HTTPS_PORT: "443"
USE_BUNKERNET: "no"
USE_BLACKLIST: "no"
SEND_ANONYMOUS_REPORT: "no"
LOG_LEVEL: "info"
# ? LETS_ENCRYPT settings
AUTO_LETS_ENCRYPT: "no"
USE_LETS_ENCRYPT_STAGING: "yes"
CUSTOM_CONF_SERVER_HTTP_ready: |
location /ready {
default_type 'text/plain';
rewrite_by_lua_block {
ngx.print('ready')
ngx.flush(true)
ngx.exit(ngx.HTTP_OK)
}
}
networks:
bw-universe:
bw-services:
ipv4_address: 192.168.0.2
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.5.6
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:nightly
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
CONTAINERS: "1"
networks:
- bw-docker
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: 192.168.0.0/24
bw-docker:
name: bw-docker

View file

View file

@ -0,0 +1,97 @@
from contextlib import suppress
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from os import getenv
from socket import create_connection
from ssl import CERT_NONE, DER_cert_to_PEM_cert, create_default_context
from requests import RequestException, get
from traceback import format_exc
from time import sleep
try:
ready = False
retries = 0
while not ready:
with suppress(RequestException):
resp = get("http://www.example.com/ready", headers={"Host": "www.example.com"}, verify=False, allow_redirects=True)
status_code = resp.status_code
text = resp.text
if status_code >= 500:
print("❌ An error occurred with the server, exiting ...", flush=True)
exit(1)
ready = status_code < 400 and text == "ready"
if retries > 10:
print("❌ The service took too long to be ready, exiting ...", flush=True)
exit(1)
elif not ready:
retries += 1
print("⚠️ Waiting for the service to be ready, retrying in 5s ...", flush=True)
sleep(5)
auto_letsencrypt = getenv("AUTO_LETS_ENCRYPT", "no") == "yes"
print(
" Sending a request to http://www.example.com ...",
flush=True,
)
try:
req = get("http://www.example.com", headers={"Host": "www.example.com"})
req.raise_for_status()
except RequestException:
if not auto_letsencrypt:
print(
"❌ The request failed even though let's Encrypt isn't activated, exiting ...",
flush=True,
)
exit(1)
if not auto_letsencrypt:
print("✅ Let's Encrypt isn't activated, as expected ...", flush=True)
exit(0)
print(
" Sending a request to https://www.example.com ...",
flush=True,
)
try:
req = get("https://www.example.com", headers={"Host": "www.example.com"}, verify=False)
req.raise_for_status()
except RequestException as e:
print(
f"❌ The request failed even though let's Encrypt is activated:\n{e}\n exiting ...",
flush=True,
)
exit(1)
sleep(1)
context = create_default_context()
context.check_hostname = False
context.verify_mode = CERT_NONE
with create_connection(("www.example.com", 443)) as sock:
with context.wrap_socket(sock, server_hostname="www.example.com") as ssock:
# Retrieve the SSL certificate
pem_data = DER_cert_to_PEM_cert(ssock.getpeercert(True))
# Parse the PEM certificate
certificate = x509.load_pem_x509_certificate(pem_data.encode(), default_backend())
common_name = certificate.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)[0].value
if common_name != "www.example.org":
print(
f"❌ Let's Encrypt is activated and the Common Name (CN) is not www.example.org (fallback one) but {common_name}, exiting ...",
flush=True,
)
exit(1)
print("✅ Let's Encrypt is activated and the Common Name (CN) is the expected one (fallback), as expected ...", flush=True)
except SystemExit as e:
exit(e.code)
except:
print(f"❌ Something went wrong, exiting ...\n{format_exc()}", flush=True)
exit(1)

View file

@ -0,0 +1,8 @@
location /ready {
default_type 'text/plain';
rewrite_by_lua_block {
ngx.print('ready')
ngx.flush(true)
ngx.exit(ngx.HTTP_OK)
}
}

View file

@ -0,0 +1,2 @@
cryptography==42.0.1
requests==2.31.0

View file

@ -0,0 +1,263 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# by the following command:
#
# pip-compile --allow-unsafe --generate-hashes --strip-extras requirements.in
#
attrs==23.2.0 \
--hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
--hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
# via
# outcome
# trio
certifi==2023.11.17 \
--hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
--hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
# via
# requests
# selenium
cffi==1.16.0 \
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
--hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
--hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
--hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
--hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
--hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
--hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
--hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
--hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
--hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
--hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
--hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
--hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
--hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
--hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
--hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
--hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
--hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
--hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
# via cryptography
charset-normalizer==3.3.2 \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via requests
cryptography==42.0.1 \
--hash=sha256:0b7cacc142260ada944de070ce810c3e2a438963ee3deb45aa26fd2cee94c9a4 \
--hash=sha256:126e0ba3cc754b200a2fb88f67d66de0d9b9e94070c5bc548318c8dab6383cb6 \
--hash=sha256:160fa08dfa6dca9cb8ad9bd84e080c0db6414ba5ad9a7470bc60fb154f60111e \
--hash=sha256:16b9260d04a0bfc8952b00335ff54f471309d3eb9d7e8dbfe9b0bd9e26e67881 \
--hash=sha256:25ec6e9e81de5d39f111a4114193dbd39167cc4bbd31c30471cebedc2a92c323 \
--hash=sha256:265bdc693570b895eb641410b8fc9e8ddbce723a669236162b9d9cfb70bd8d77 \
--hash=sha256:2dff7a32880a51321f5de7869ac9dde6b1fca00fc1fef89d60e93f215468e824 \
--hash=sha256:2fe16624637d6e3e765530bc55caa786ff2cbca67371d306e5d0a72e7c3d0407 \
--hash=sha256:32ea63ceeae870f1a62e87f9727359174089f7b4b01e4999750827bf10e15d60 \
--hash=sha256:351db02c1938c8e6b1fee8a78d6b15c5ccceca7a36b5ce48390479143da3b411 \
--hash=sha256:430100abed6d3652208ae1dd410c8396213baee2e01a003a4449357db7dc9e14 \
--hash=sha256:4d84673c012aa698555d4710dcfe5f8a0ad76ea9dde8ef803128cc669640a2e0 \
--hash=sha256:50aecd93676bcca78379604ed664c45da82bc1241ffb6f97f6b7392ed5bc6f04 \
--hash=sha256:6ac8924085ed8287545cba89dc472fc224c10cc634cdf2c3e2866fe868108e77 \
--hash=sha256:6bfd823b336fdcd8e06285ae8883d3d2624d3bdef312a0e2ef905f332f8e9302 \
--hash=sha256:727387886c9c8de927c360a396c5edcb9340d9e960cda145fca75bdafdabd24c \
--hash=sha256:7911586fc69d06cd0ab3f874a169433db1bc2f0e40988661408ac06c4527a986 \
--hash=sha256:802d6f83233cf9696b59b09eb067e6b4d5ae40942feeb8e13b213c8fad47f1aa \
--hash=sha256:8d7efb6bf427d2add2f40b6e1e8e476c17508fa8907234775214b153e69c2e11 \
--hash=sha256:9544492e8024f29919eac2117edd8c950165e74eb551a22c53f6fdf6ba5f4cb8 \
--hash=sha256:95d900d19a370ae36087cc728e6e7be9c964ffd8cbcb517fd1efb9c9284a6abc \
--hash=sha256:9d61fcdf37647765086030d81872488e4cb3fafe1d2dda1d487875c3709c0a49 \
--hash=sha256:ab6b302d51fbb1dd339abc6f139a480de14d49d50f65fdc7dff782aa8631d035 \
--hash=sha256:b512f33c6ab195852595187af5440d01bb5f8dd57cb7a91e1e009a17f1b7ebca \
--hash=sha256:cb2861a9364fa27d24832c718150fdbf9ce6781d7dc246a516435f57cfa31fe7 \
--hash=sha256:d3594947d2507d4ef7a180a7f49a6db41f75fb874c2fd0e94f36b89bfd678bf2 \
--hash=sha256:d3902c779a92151f134f68e555dd0b17c658e13429f270d8a847399b99235a3f \
--hash=sha256:d50718dd574a49d3ef3f7ef7ece66ef281b527951eb2267ce570425459f6a404 \
--hash=sha256:e5edf189431b4d51f5c6fb4a95084a75cef6b4646c934eb6e32304fc720e1453 \
--hash=sha256:e6edc3a568667daf7d349d7e820783426ee4f1c0feab86c29bd1d6fe2755e009 \
--hash=sha256:ed1b2130f5456a09a134cc505a17fc2830a1a48ed53efd37dcc904a23d7b82fa \
--hash=sha256:fd33f53809bb363cf126bebe7a99d97735988d9b0131a2be59fbf83e1259a5b7
# via -r requirements.in
exceptiongroup==1.2.0 \
--hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14 \
--hash=sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68
# via
# trio
# trio-websocket
h11==0.14.0 \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
# via wsproto
idna==3.6 \
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
# via
# requests
# trio
outcome==1.3.0.post0 \
--hash=sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8 \
--hash=sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b
# via trio
pycparser==2.21 \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
# via cffi
pysocks==1.7.1 \
--hash=sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299 \
--hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5 \
--hash=sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0
# via urllib3
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
# via -r requirements.in
selenium==4.16.0 \
--hash=sha256:aec71f4e6ed6cb3ec25c9c1b5ed56ae31b6da0a7f17474c7566d303f84e6219f \
--hash=sha256:b2e987a445306151f7be0e6dfe2aa72a479c2ac6a91b9d5ef2d6dd4e49ad0435
# via -r requirements.in
sniffio==1.3.0 \
--hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
--hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
# via trio
sortedcontainers==2.4.0 \
--hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \
--hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0
# via trio
trio==0.24.0 \
--hash=sha256:c3bd3a4e3e3025cd9a2241eae75637c43fe0b9e88b4c97b9161a55b9e54cd72c \
--hash=sha256:ffa09a74a6bf81b84f8613909fb0beaee84757450183a7a2e0b47b455c0cac5d
# via
# selenium
# trio-websocket
trio-websocket==0.11.1 \
--hash=sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f \
--hash=sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638
# via selenium
urllib3==2.1.0 \
--hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
--hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
# via
# requests
# selenium
wsproto==1.2.0 \
--hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \
--hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736
# via trio-websocket

216
tests/core/letsencrypt/test.sh Executable file
View file

@ -0,0 +1,216 @@
#!/bin/bash
integration=$1
if [ -z "$integration" ] ; then
echo "🔒 Please provide an integration name as argument ❌"
exit 1
elif [ "$integration" != "docker" ] && [ "$integration" != "linux" ] ; then
echo "🔒 Integration \"$integration\" is not supported ❌"
exit 1
fi
echo "🔒 Building letsencrypt stack for integration \"$integration\" ..."
# Starting stack
if [ "$integration" == "docker" ] ; then
docker compose pull bw-docker
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Pull failed ❌"
exit 1
fi
docker compose -f docker-compose.test.yml build
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Build failed ❌"
exit 1
fi
else
sudo systemctl stop bunkerweb
echo "AUTO_LETS_ENCRYPT=no" | sudo tee -a /etc/bunkerweb/variables.env
echo "USE_LETS_ENCRYPT_STAGING=yes" | sudo tee -a /etc/bunkerweb/variables.env
sudo touch /var/www/html/index.html
sudo cp ready.conf /etc/bunkerweb/configs/server-http
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
if [ "$integration" == "docker" ] ; then
find . -type f -name 'docker-compose.*' -exec sed -i 's@AUTO_LETS_ENCRYPT: "yes"@AUTO_LETS_ENCRYPT: "no"@' {} \;
find . -type f -name 'docker-compose.*' -exec sed -i 's@USE_LETS_ENCRYPT_STAGING: "no"@USE_LETS_ENCRYPT_STAGING: "yes"@' {} \;
else
sudo sed -i '$ d' /etc/bunkerweb/variables.env
sudo sed -i '$ d' /etc/bunkerweb/variables.env
unset AUTO_LETS_ENCRYPT
fi
if [[ $end -eq 1 && $exit_code = 0 ]] ; then
return
fi
fi
echo "🔒 Cleaning up current stack ..."
if [ "$integration" == "docker" ] ; then
docker compose down -v --remove-orphans
else
sudo systemctl stop bunkerweb
sudo truncate -s 0 /var/log/bunkerweb/error.log
fi
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Cleanup failed ❌"
exit 1
fi
echo "🔒 Cleaning up current stack done ✅"
}
# Cleanup stack on exit
trap cleanup_stack EXIT
for test in "deactivated" "fallback"
do
if [ "$test" = "deactivated" ] ; then
echo "🔒 Running tests without letsencrypt ..."
elif [ "$test" = "fallback" ] ; then
echo "🔒 Running tests with letsencrypt activated and fallback to default cert ..."
if [ "$integration" == "docker" ] ; then
find . -type f -name 'docker-compose.*' -exec sed -i 's@AUTO_LETS_ENCRYPT: "no"@AUTO_LETS_ENCRYPT: "yes"@' {} \;
else
sudo sed -i 's@AUTO_LETS_ENCRYPT=no$@AUTO_LETS_ENCRYPT=yes@' /etc/bunkerweb/variables.env
export AUTO_LETS_ENCRYPT="yes"
fi
fi
echo "🔒 Starting stack ..."
if [ "$integration" == "docker" ] ; then
docker compose up -d
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Up failed, retrying ... ⚠️"
manual=1
cleanup_stack
manual=0
docker compose up -d
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Up failed ❌"
exit 1
fi
fi
else
sudo systemctl start bunkerweb
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Start failed ❌"
exit 1
fi
fi
# Check if stack is healthy
echo "🔒 Waiting for stack to be healthy ..."
i=0
if [ "$integration" == "docker" ] ; then
while [ $i -lt 120 ] ; do
containers=("letsencrypt-bw-1" "letsencrypt-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
else
healthy="false"
retries=0
while [[ $healthy = "false" && $retries -lt 5 ]] ; do
while [ $i -lt 120 ] ; do
if sudo grep -q "BunkerWeb is ready" "/var/log/bunkerweb/error.log" ; then
echo "🔒 Linux stack is healthy ✅"
break
fi
sleep 1
i=$((i+1))
done
if [ $i -ge 120 ] ; then
sudo journalctl -u bunkerweb --no-pager
echo "🛡️ Showing BunkerWeb error logs ..."
sudo cat /var/log/bunkerweb/error.log
echo "🛡️ Showing BunkerWeb access logs ..."
sudo cat /var/log/bunkerweb/access.log
echo "🔒 Linux stack is not healthy ❌"
exit 1
fi
if sudo journalctl -u bunkerweb --no-pager | grep -q "SYSTEMCTL - ❌ " ; then
echo "🔒 ⚠ Linux stack got an issue, restarting ..."
sudo journalctl --rotate
sudo journalctl --vacuum-time=1s
manual=1
cleanup_stack
manual=0
sudo systemctl start bunkerweb
retries=$((retries+1))
else
healthy="true"
fi
done
if [ "$retries" -ge 5 ] ; then
echo "🔒 Linux stack could not be healthy ❌"
exit 1
fi
fi
# Start tests
if [ "$integration" == "docker" ] ; then
docker compose -f docker-compose.test.yml up --abort-on-container-exit --exit-code-from tests
else
python3 main.py
fi
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo "🔒 Test \"$test\" failed ❌"
echo "🛡️ Showing BunkerWeb and BunkerWeb Scheduler logs ..."
if [ "$integration" == "docker" ] ; then
docker compose logs bw bw-scheduler
else
sudo journalctl -u bunkerweb --no-pager
echo "🛡️ Showing BunkerWeb error logs ..."
sudo cat /var/log/bunkerweb/error.log
echo "🛡️ Showing BunkerWeb access logs ..."
sudo cat /var/log/bunkerweb/access.log
fi
exit 1
else
echo "🔒 Test \"$test\" succeeded ✅"
fi
manual=1
cleanup_stack
manual=0
echo " "
done
end=1
echo "🔒 Tests are done ! ✅"

View file

@ -147,7 +147,7 @@ def access_page(
title = driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/div/header/div/nav/h6")))
if title.text != name.replace(" ", "_").title():
if title.text != name.title():
print(f"Didn't get redirected to {name} page, exiting ...", flush=True)
exit(1)
except TimeoutException:
@ -538,17 +538,11 @@ with driver_func() as driver:
print("Checking the services page ...", flush=True)
try:
service = safe_get_element(driver, By.XPATH, "//div[@data-services-service='']", error=True)
except TimeoutException:
print("Services not found, exiting ...", flush=True)
exit(1)
if service.find_element(By.TAG_NAME, "h5").text.strip() != "www.example.com":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='www.example.com']//h5").text.strip() != "www.example.com":
print("The service is not present, exiting ...", flush=True)
exit(1)
if service.find_element(By.TAG_NAME, "h6").text.strip() != "ui":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='www.example.com']//h6").text.strip() != "ui":
print(
"The service should have been created by the ui, exiting ...",
flush=True,
@ -559,7 +553,7 @@ with driver_func() as driver:
assert_button_click(
driver,
service.find_element(By.XPATH, ".//button[@data-services-action='edit']"),
"//div[@data-services-service='www.example.com']//button[@data-services-action='edit']",
)
try:
@ -637,15 +631,9 @@ with driver_func() as driver:
flush=True,
)
try:
service = safe_get_element(driver, By.XPATH, "//div[@data-services-service='']", error=True)
except TimeoutException:
print("Services not found, exiting ...", flush=True)
exit(1)
assert_button_click(
driver,
service.find_element(By.XPATH, ".//button[@data-services-action='edit']"),
"//div[@data-services-service='www.example.com']//button[@data-services-action='edit']",
)
modal = safe_get_element(driver, By.XPATH, "//div[@data-services-modal='']")
@ -717,13 +705,7 @@ with driver_func() as driver:
sleep(5)
try:
services = safe_get_element(
driver,
By.XPATH,
"//div[@data-services-service='']",
multiple=True,
error=True,
)
services = safe_get_element(driver, By.XPATH, "//div[@data-services-service]", multiple=True, error=True)
except TimeoutException:
print("Services not found, exiting ...", flush=True)
exit(1)
@ -732,13 +714,11 @@ with driver_func() as driver:
print("The service hasn't been created, exiting ...", flush=True)
exit(1)
service = services[0]
if service.find_element(By.TAG_NAME, "h5").text.strip() != "app1.example.com":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='app1.example.com']//h5").text.strip() != "app1.example.com":
print('The service "app1.example.com" is not present, exiting ...', flush=True)
exit(1)
if service.find_element(By.TAG_NAME, "h6").text.strip() != "ui":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='app1.example.com']//h6").text.strip() != "ui":
print(
"The service should have been created by the ui, exiting ...",
flush=True,
@ -843,13 +823,7 @@ with driver_func() as driver:
sleep(5)
try:
services = safe_get_element(
driver,
By.XPATH,
"//div[@data-services-service='']",
multiple=True,
error=True,
)
services = safe_get_element(driver, By.XPATH, "//div[@data-services-service]", multiple=True, error=True)
except TimeoutException:
print("Services not found, exiting ...", flush=True)
exit(1)
@ -858,13 +832,11 @@ with driver_func() as driver:
print("The service hasn't been created, exiting ...", flush=True)
exit(1)
service = services[1]
if service.find_element(By.TAG_NAME, "h5").text.strip() != "app2.example.com":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='app2.example.com']//h5").text.strip() != "app2.example.com":
print('The service "app2.example.com" is not present, exiting ...', flush=True)
exit(1)
if service.find_element(By.TAG_NAME, "h6").text.strip() != "ui":
if safe_get_element(driver, By.XPATH, "//div[@data-services-service='app2.example.com']//h6").text.strip() != "ui":
print(
"The service should have been created by the ui, exiting ...",
flush=True,
@ -972,13 +944,7 @@ with driver_func() as driver:
)
try:
services = safe_get_element(
driver,
By.XPATH,
"//div[@data-services-service='']",
multiple=True,
error=True,
)
services = safe_get_element(driver, By.XPATH, "//div[@data-services-service='']", multiple=True, error=True)
except TimeoutException:
print("Services not found, exiting ...", flush=True)
exit(1)