mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Merge pull request #1282 from bunkerity/dev
Merge branch "dev" into branch "staging"
This commit is contained in:
commit
18517b9553
11 changed files with 183 additions and 115 deletions
|
|
@ -330,7 +330,7 @@ Here is the list of related settings :
|
|||
| --------------------------- | ------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `USE_ANTIBOT` | `no` | multisite | no | Activate antibot feature. |
|
||||
| `ANTIBOT_URI` | `/challenge` | multisite | no | Unused URI that clients will be redirected to to solve the challenge. |
|
||||
| `ANTIBOT_RECAPTCHA_SCORE` | `0.7` | multisite | no | Minimum score required for reCAPTCHA challenge. |
|
||||
| `ANTIBOT_RECAPTCHA_SCORE` | `0.7` | multisite | no | Minimum score required for reCAPTCHA challenge (Only compatible with reCAPTCHA v3). |
|
||||
| `ANTIBOT_RECAPTCHA_SITEKEY` | | multisite | no | Sitekey for reCAPTCHA challenge. |
|
||||
| `ANTIBOT_RECAPTCHA_SECRET` | | multisite | no | Secret for reCAPTCHA challenge. |
|
||||
| `ANTIBOT_HCAPTCHA_SITEKEY` | | multisite | no | Sitekey for hCaptcha challenge. |
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ Bot detection by using a challenge.
|
|||
|`ANTIBOT_URI` |`/challenge`|multisite|no |Unused URI that clients will be redirected to to solve the challenge. |
|
||||
|`ANTIBOT_TIME_RESOLVE` |`60` |multisite|no |Maximum time (in seconds) clients have to resolve the challenge. Once this time has passed, a new challenge will be generated.|
|
||||
|`ANTIBOT_TIME_VALID` |`86400` |multisite|no |Maximum validity time of solved challenges. Once this time has passed, clients will need to resolve a new one. |
|
||||
|`ANTIBOT_RECAPTCHA_SCORE` |`0.7` |multisite|no |Minimum score required for reCAPTCHA challenge. |
|
||||
|`ANTIBOT_RECAPTCHA_SCORE` |`0.7` |multisite|no |Minimum score required for reCAPTCHA challenge (Only compatible with reCAPTCHA v3). |
|
||||
|`ANTIBOT_RECAPTCHA_SITEKEY`| |multisite|no |Sitekey for reCAPTCHA challenge. |
|
||||
|`ANTIBOT_RECAPTCHA_SECRET` | |multisite|no |Secret for reCAPTCHA challenge. |
|
||||
|`ANTIBOT_HCAPTCHA_SITEKEY` | |multisite|no |Sitekey for hCaptcha challenge. |
|
||||
|
|
|
|||
|
|
@ -46,8 +46,12 @@ class Config:
|
|||
if not server_name:
|
||||
continue
|
||||
for variable, value in service.items():
|
||||
if self._db.is_setting(variable, multisite=True):
|
||||
config[f"{server_name}_{variable}"] = value
|
||||
if variable.startswith("CUSTOM_CONF") or not variable.isupper():
|
||||
continue
|
||||
if not self._db.is_setting(variable, multisite=True):
|
||||
self.__logger.warning(f"Variable {variable}: {value} is not a valid multisite setting, ignoring it")
|
||||
continue
|
||||
config[f"{server_name}_{variable}"] = value
|
||||
config["SERVER_NAME"] += f" {server_name}"
|
||||
config["SERVER_NAME"] = config["SERVER_NAME"].strip()
|
||||
return config
|
||||
|
|
@ -134,6 +138,7 @@ class Config:
|
|||
|
||||
# update instances in database
|
||||
if "instances" in changes:
|
||||
self.__logger.debug(f"Updating instances in database: {self.__instances}")
|
||||
err = self._db.update_instances(self.__instances, changed=False)
|
||||
if err:
|
||||
self.__logger.error(f"Failed to update instances: {err}")
|
||||
|
|
@ -141,6 +146,7 @@ class Config:
|
|||
# save config to database
|
||||
changed_plugins = []
|
||||
if "config" in changes:
|
||||
self.__logger.debug(f"Saving config in database: {self.__config}")
|
||||
err = self._db.save_config(self.__config, "autoconf", changed=False)
|
||||
if isinstance(err, str):
|
||||
success = False
|
||||
|
|
@ -149,6 +155,7 @@ class Config:
|
|||
|
||||
# save custom configs to database
|
||||
if "custom_configs" in changes:
|
||||
self.__logger.debug(f"Saving custom configs in database: {custom_configs}")
|
||||
err = self._db.save_custom_configs(custom_configs, "autoconf", changed=False)
|
||||
if err:
|
||||
success = False
|
||||
|
|
|
|||
|
|
@ -256,6 +256,15 @@
|
|||
</div>
|
||||
<!-- text -->
|
||||
|
||||
{-raw-}
|
||||
<script nonce="{{ nonce_script }}">
|
||||
// Automatically refresh the page after 2 seconds
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
</script>
|
||||
{-raw-}
|
||||
|
||||
<footer class="fixed bottom-1.5 lg:bottom-2">
|
||||
<div class="flex justify-center pb-2">
|
||||
<img
|
||||
|
|
|
|||
|
|
@ -67,18 +67,22 @@ server {
|
|||
end
|
||||
|
||||
local nonce_style = rand(16)
|
||||
local nonce_script = rand(16)
|
||||
|
||||
-- Override CSP header
|
||||
ngx.header["Content-Security-Policy"] = "default-src 'none'; form-action 'self'; img-src 'self' data:; style-src 'self' 'nonce-"
|
||||
ngx.header["Content-Security-Policy"] = "default-src 'none'; script-src http: https: 'unsafe-inline' 'strict-dynamic' 'nonce-"
|
||||
.. nonce_script
|
||||
.. "'; style-src 'nonce-"
|
||||
.. nonce_style
|
||||
.. "'; font-src 'self' data:; base-uri 'self'; require-trusted-types-for 'script';"
|
||||
.. "'; base-uri 'none'; img-src 'self' data:; font-src 'self' data:; require-trusted-types-for 'script';"
|
||||
|
||||
-- Remove server header
|
||||
ngx.header["Server"] = nil
|
||||
|
||||
-- Render template
|
||||
render("index.html", {
|
||||
nonce_style = nonce_style
|
||||
nonce_style = nonce_style,
|
||||
nonce_script = nonce_script
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,42 +60,36 @@ function antibot:header()
|
|||
return self:ret(true, "client already resolved the challenge", nil, self.session_data.original_uri)
|
||||
end
|
||||
|
||||
-- Override headers
|
||||
local header = "Content-Security-Policy"
|
||||
if self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes" then
|
||||
header = header .. "-Report-Only"
|
||||
end
|
||||
-- Override CSP header
|
||||
local csp_directives = {
|
||||
["default-src"] = "'none'",
|
||||
["base-uri"] = "'none'",
|
||||
["img-src"] = "'self' data:",
|
||||
["font-src"] = "'self' data:",
|
||||
["script-src"] = "http: https: 'unsafe-inline' 'strict-dynamic' 'nonce-"
|
||||
.. self.ctx.bw.antibot_nonce_script
|
||||
.. "'",
|
||||
["style-src"] = "'self' 'nonce-" .. self.ctx.bw.antibot_nonce_style .. "'",
|
||||
["require-trusted-types-for"] = "'script'",
|
||||
}
|
||||
if self.session_data.type == "recaptcha" then
|
||||
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
|
||||
.. self.session_data.nonce_script
|
||||
.. "' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-inline' http: https:;"
|
||||
.. " img-src https://www.gstatic.com/recaptcha/ 'self' data:; "
|
||||
.. " frame-src https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/;"
|
||||
.. " style-src 'self' 'nonce-"
|
||||
.. self.session_data.nonce_style
|
||||
.. "'; font-src 'self' https://fonts.gstatic.com data:; base-uri 'self';"
|
||||
csp_directives["script-src"] = csp_directives["script-src"]
|
||||
.. " https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/"
|
||||
csp_directives["frame-src"] = "https://www.google.com/recaptcha/ https://recaptcha.google.com/recaptcha/"
|
||||
elseif self.session_data.type == "hcaptcha" then
|
||||
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
|
||||
.. self.session_data.nonce_script
|
||||
.. "' https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' http: https:; img-src 'self' data:;"
|
||||
.. " frame-src https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' 'nonce-"
|
||||
.. self.session_data.nonce_style
|
||||
.. "' https://hcaptcha.com https://*.hcaptcha.com; connect-src https://hcaptcha.com https://*.hcaptcha.com; "
|
||||
.. " font-src 'self' data:; base-uri 'self';"
|
||||
csp_directives["script-src"] = csp_directives["script-src"] .. " https://hcaptcha.com https://*.hcaptcha.com"
|
||||
csp_directives["frame-src"] = "https://hcaptcha.com https://*.hcaptcha.com"
|
||||
csp_directives["style-src"] = csp_directives["style-src"] .. " https://hcaptcha.com https://*.hcaptcha.com"
|
||||
csp_directives["connect-src"] = "https://hcaptcha.com https://*.hcaptcha.com"
|
||||
elseif self.session_data.type == "turnstile" then
|
||||
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
|
||||
.. self.session_data.nonce_script
|
||||
.. "' https://challenges.cloudflare.com 'unsafe-inline' http: https:; img-src 'self' data:;"
|
||||
.. " frame-src https://challenges.cloudflare.com; style-src 'self' 'nonce-"
|
||||
.. self.session_data.nonce_style
|
||||
.. "'; font-src 'self' data:; base-uri 'self';"
|
||||
else
|
||||
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
|
||||
.. self.session_data.nonce_script
|
||||
.. "' 'unsafe-inline' http: https:; img-src 'self' data:; style-src 'self' 'nonce-"
|
||||
.. self.session_data.nonce_style
|
||||
.. "'; font-src 'self' data:; base-uri 'self';"
|
||||
csp_directives["script-src"] = csp_directives["script-src"] .. " https://challenges.cloudflare.com"
|
||||
csp_directives["frame-src"] = "https://challenges.cloudflare.com"
|
||||
end
|
||||
local csp_content = ""
|
||||
for directive, value in pairs(csp_directives) do
|
||||
csp_content = csp_content .. directive .. " " .. value .. "; "
|
||||
end
|
||||
ngx.header["Content-Security-Policy"] = csp_content
|
||||
return self:ret(true, "successfully overridden CSP header")
|
||||
end
|
||||
|
||||
|
|
@ -192,6 +186,9 @@ function antibot:content()
|
|||
return self:ret(true, "no session", nil, "/")
|
||||
end
|
||||
|
||||
self.ctx.bw.antibot_nonce_script = rand(32)
|
||||
self.ctx.bw.antibot_nonce_style = rand(32)
|
||||
|
||||
-- Display content
|
||||
local ok, err = self:display_challenge()
|
||||
if not ok then
|
||||
|
|
@ -242,8 +239,6 @@ function antibot:prepare_challenge()
|
|||
self.session_data.type = self.variables["USE_ANTIBOT"]
|
||||
self.session_data.resolved = false
|
||||
self.session_data.original_uri = self.ctx.bw.request_uri
|
||||
self.session_data.nonce_script = rand(16)
|
||||
self.session_data.nonce_style = rand(16)
|
||||
if self.ctx.bw.uri == self.variables["ANTIBOT_URI"] then
|
||||
self.session_data.original_uri = "/"
|
||||
end
|
||||
|
|
@ -268,8 +263,8 @@ function antibot:display_challenge()
|
|||
-- Common variables for templates
|
||||
local template_vars = {
|
||||
antibot_uri = self.variables["ANTIBOT_URI"],
|
||||
nonce_script = self.session_data.nonce_script,
|
||||
nonce_style = self.session_data.nonce_style,
|
||||
nonce_script = self.ctx.bw.antibot_nonce_script,
|
||||
nonce_style = self.ctx.bw.antibot_nonce_style,
|
||||
}
|
||||
|
||||
-- Javascript case
|
||||
|
|
@ -387,7 +382,10 @@ function antibot:check_challenge()
|
|||
if not ok then
|
||||
return nil, "error while decoding JSON from reCAPTCHA API : " .. rdata, nil
|
||||
end
|
||||
if not rdata.success or rdata.score < tonumber(self.variables["ANTIBOT_RECAPTCHA_SCORE"]) then
|
||||
if not rdata.success then
|
||||
return false, "client failed challenge", nil
|
||||
end
|
||||
if rdata.score and rdata.score < tonumber(self.variables["ANTIBOT_RECAPTCHA_SCORE"]) then
|
||||
return false, "client failed challenge with score " .. tostring(rdata.score), nil
|
||||
end
|
||||
self.session_data.resolved = true
|
||||
|
|
|
|||
113
src/common/core/antibot/files/recaptcha.html
vendored
113
src/common/core/antibot/files/recaptcha.html
vendored
|
|
@ -22,6 +22,65 @@
|
|||
margin-top: 1rem
|
||||
}
|
||||
</style>
|
||||
{-raw-}
|
||||
<script
|
||||
src="https://www.google.com/recaptcha/api.js?onload=onv3Callback&render={*recaptcha_sitekey*}&trustedtypes=true"
|
||||
nonce="{*nonce_script*}"
|
||||
></script>
|
||||
<script
|
||||
defer
|
||||
src="https://www.google.com/recaptcha/api.js?onload=onv2Callback&trustedtypes=true"
|
||||
nonce="{*nonce_script*}"
|
||||
></script>
|
||||
<script type="text/javascript" nonce="{*nonce_script*}">
|
||||
var onSubmit = function (token) {
|
||||
document.getElementById("token").value = token;
|
||||
document.getElementById("form").submit();
|
||||
};
|
||||
|
||||
var usedVersion = "v2";
|
||||
|
||||
var onv2Callback = function () {
|
||||
if (usedVersion === "invisible") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the v3 button
|
||||
document.getElementById("recaptcha-verify").remove();
|
||||
|
||||
// Insert the v2 div
|
||||
var recaptchaDiv = document.createElement("div");
|
||||
recaptchaDiv.id = "recaptcha-v2-verify";
|
||||
recaptchaDiv.className = "g-recaptcha";
|
||||
recaptchaDiv.setAttribute("data-sitekey", "{*recaptcha_sitekey*}");
|
||||
recaptchaDiv.setAttribute("data-callback", "onSubmit");
|
||||
recaptchaDiv.setAttribute("data-action", "submit");
|
||||
document
|
||||
.getElementById("recaptcha-container")
|
||||
.appendChild(recaptchaDiv);
|
||||
|
||||
grecaptcha.ready(function () {
|
||||
grecaptcha.render("recaptcha-v2-verify", {
|
||||
sitekey: "{*recaptcha_sitekey*}",
|
||||
callback: onSubmit,
|
||||
action: "submit",
|
||||
});
|
||||
document.querySelector(".grecaptcha-badge").remove();
|
||||
});
|
||||
};
|
||||
|
||||
var onv3Callback = function () {
|
||||
usedVersion = "invisible";
|
||||
grecaptcha.ready(function () {
|
||||
document
|
||||
.getElementById("recaptcha-verify")
|
||||
.addEventListener("click", function () {
|
||||
grecaptcha.execute();
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
{-raw-}
|
||||
</head>
|
||||
<body
|
||||
class="bg-gradient-to-r from-[#075577] to-[#116D70] w-screen h-screen overflow-hidden"
|
||||
|
|
@ -255,14 +314,19 @@
|
|||
<form class="hidden" method="POST" action="{*antibot_uri*}" id="form">
|
||||
<input type="hidden" name="token" id="token" />
|
||||
</form>
|
||||
{-raw-}
|
||||
<div class="mt-8 flex flex-col justify-center items-center">
|
||||
<button
|
||||
id="recaptcha-verify"
|
||||
class="text-sm xs:text-base mb-2.5 hover:brightness-90 mt-2 rounded-lg bg-secondary px-6 py-2 text-white font-bold"
|
||||
>
|
||||
I'm not a robot
|
||||
</button>
|
||||
<div id="recaptcha-container">
|
||||
<button
|
||||
id="recaptcha-verify"
|
||||
class="g-recaptcha text-sm xs:text-base mb-2.5 hover:brightness-90 mt-2 rounded-lg bg-secondary px-6 py-2 text-white font-bold"
|
||||
data-sitekey="{*recaptcha_sitekey*}"
|
||||
data-callback="onSubmit"
|
||||
data-action="submit"
|
||||
>
|
||||
I'm not a robot
|
||||
</button>
|
||||
</div>
|
||||
{-raw-}
|
||||
<p
|
||||
id="recaptcha-terms"
|
||||
class="text-gray-100 text-center text-xs sm:text-sm"
|
||||
|
|
@ -284,41 +348,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{-raw-}
|
||||
<script nonce="{*nonce_script*}">
|
||||
// recaptcha
|
||||
const check_robot = function () {
|
||||
grecaptcha.ready(function () {
|
||||
grecaptcha
|
||||
.execute("{*recaptcha_sitekey*}", { action: "recaptcha" })
|
||||
.then(function (token) {
|
||||
document.getElementById("token").value = token;
|
||||
document.getElementById("form").submit();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var cooldown = false;
|
||||
|
||||
document
|
||||
.getElementById("recaptcha-verify")
|
||||
.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
if (cooldown) return;
|
||||
cooldown = true;
|
||||
check_robot();
|
||||
setTimeout(() => {
|
||||
cooldown = false;
|
||||
}, 1500);
|
||||
});
|
||||
</script>
|
||||
<script
|
||||
async
|
||||
src="https://www.google.com/recaptcha/api.js?render={*recaptcha_sitekey*}"
|
||||
nonce="{*nonce_script*}"
|
||||
></script>
|
||||
{-raw-}
|
||||
|
||||
<!-- text -->
|
||||
<footer class="fixed bottom-1.5 lg:bottom-2">
|
||||
<div class="flex justify-center pb-2">
|
||||
|
|
|
|||
1
src/common/core/antibot/files/turnstile.html
vendored
1
src/common/core/antibot/files/turnstile.html
vendored
|
|
@ -22,7 +22,6 @@
|
|||
</style>
|
||||
{-raw-}
|
||||
<script
|
||||
async
|
||||
defer
|
||||
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
|
||||
nonce="{*nonce_script*}"
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@
|
|||
"ANTIBOT_RECAPTCHA_SCORE": {
|
||||
"context": "multisite",
|
||||
"default": "0.7",
|
||||
"help": "Minimum score required for reCAPTCHA challenge.",
|
||||
"help": "Minimum score required for reCAPTCHA challenge (Only compatible with reCAPTCHA v3).",
|
||||
"id": "antibot-recaptcha-score",
|
||||
"label": "reCAPTCHA score",
|
||||
"label": "reCAPTCHA v3 score",
|
||||
"regex": "^(0\\.[1-9]|1\\.0)$",
|
||||
"type": "text"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -394,9 +394,20 @@ class Database:
|
|||
"""Check if the setting exists in the database and optionally if it's multisite"""
|
||||
with self.__db_session() as session:
|
||||
try:
|
||||
if multisite:
|
||||
return session.query(Settings).filter_by(id=setting, context="multisite").first() is not None
|
||||
return session.query(Settings).filter_by(id=setting).first() is not None
|
||||
multiple = False
|
||||
if self.suffix_rx.search(setting):
|
||||
setting = setting.rsplit("_", 1)[0]
|
||||
multiple = True
|
||||
|
||||
db_setting = session.query(Settings).filter_by(id=setting).first()
|
||||
|
||||
if not db_setting:
|
||||
return False
|
||||
elif multisite and db_setting.context != "multisite":
|
||||
return False
|
||||
elif multiple and db_setting.multiple is None:
|
||||
return False
|
||||
return True
|
||||
except (ProgrammingError, OperationalError):
|
||||
return False
|
||||
|
||||
|
|
@ -1575,25 +1586,24 @@ class Database:
|
|||
if global_value.context == "multisite":
|
||||
multisite.add(setting_id)
|
||||
|
||||
is_multisite = config.get("MULTISITE", {"value": "no"})["value"] == "yes" if methods else config.get("MULTISITE", "no") == "yes"
|
||||
|
||||
services = session.query(Services).with_entities(Services.id, Services.is_draft)
|
||||
|
||||
if not with_drafts:
|
||||
services = services.filter_by(is_draft=False)
|
||||
|
||||
servers = ""
|
||||
for service in services:
|
||||
if not global_only:
|
||||
if not global_only and is_multisite:
|
||||
servers = ""
|
||||
for service in services:
|
||||
config[f"{service.id}_IS_DRAFT"] = "yes" if service.is_draft else "no"
|
||||
if methods:
|
||||
config[f"{service.id}_IS_DRAFT"] = {"value": config[f"{service.id}_IS_DRAFT"], "global": False, "method": "default"}
|
||||
for key in multisite:
|
||||
config[f"{service.id}_{key}"] = config[key]
|
||||
servers += f"{service.id} "
|
||||
servers = servers.strip()
|
||||
servers += f"{service.id} "
|
||||
servers = servers.strip()
|
||||
|
||||
config["SERVER_NAME"] = servers if not methods else {"value": servers, "global": True, "method": "default"}
|
||||
|
||||
if not global_only and (config.get("MULTISITE", {"value": "no"})["value"] == "yes" if methods else config.get("MULTISITE", "no") == "yes"):
|
||||
# Define the join operation
|
||||
j = join(Services, Services_settings, Services.id == Services_settings.service_id)
|
||||
j = j.join(Settings, Settings.id == Services_settings.setting_id)
|
||||
|
|
@ -1632,6 +1642,10 @@ class Database:
|
|||
config[f"{result.service_id}_{result.setting_id}" + (f"_{result.suffix}" if result.multiple and result.suffix else "")] = (
|
||||
value if not methods else {"value": value, "global": False, "method": result.method}
|
||||
)
|
||||
else:
|
||||
servers = " ".join(service.id for service in services)
|
||||
|
||||
config["SERVER_NAME"] = servers if not methods else {"value": servers, "global": True, "method": "default"}
|
||||
|
||||
return config
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,15 @@ def send_nginx_custom_configs(sent_path: Path = CUSTOM_CONFIGS_PATH):
|
|||
logger.info(f"Successfully sent {sent_path} folder")
|
||||
|
||||
|
||||
def send_nginx_external_plugins(sent_path: Path = EXTERNAL_PLUGINS_PATH):
|
||||
assert SCHEDULER is not None, "SCHEDULER is not defined"
|
||||
logger.info(f"Sending {sent_path} folder ...")
|
||||
if not SCHEDULER.send_files(sent_path.as_posix(), "/pro_plugins" if sent_path.as_posix().endswith("/pro/plugins") else "/plugins"):
|
||||
logger.error(f"Error while sending {sent_path} folder")
|
||||
else:
|
||||
logger.info(f"Successfully sent {sent_path} folder")
|
||||
|
||||
|
||||
def listen_for_instances_reload():
|
||||
from docker import DockerClient
|
||||
|
||||
|
|
@ -236,15 +245,14 @@ def generate_custom_configs(configs: Optional[List[Dict[str, Any]]] = None, *, o
|
|||
send_nginx_custom_configs(original_path)
|
||||
|
||||
|
||||
def generate_external_plugins(plugins: Optional[List[Dict[str, Any]]] = None, *, original_path: Union[Path, str] = EXTERNAL_PLUGINS_PATH):
|
||||
def generate_external_plugins(original_path: Union[Path, str] = EXTERNAL_PLUGINS_PATH):
|
||||
if not isinstance(original_path, Path):
|
||||
original_path = Path(original_path)
|
||||
pro = "pro" in original_path.parts
|
||||
pro = original_path.as_posix().endswith("/pro/plugins")
|
||||
|
||||
if not plugins:
|
||||
assert SCHEDULER is not None
|
||||
plugins = SCHEDULER.db.get_plugins(_type="pro" if pro else "external", with_data=True)
|
||||
assert plugins is not None, "Couldn't get plugins from database"
|
||||
assert SCHEDULER is not None
|
||||
plugins = SCHEDULER.db.get_plugins(_type="pro" if pro else "external", with_data=True)
|
||||
assert plugins is not None, "Couldn't get plugins from database"
|
||||
|
||||
# Remove old external/pro plugins files
|
||||
logger.info(f"Removing old/changed {'pro ' if pro else ''}external plugins files ...")
|
||||
|
|
@ -299,10 +307,7 @@ def generate_external_plugins(plugins: Optional[List[Dict[str, Any]]] = None, *,
|
|||
|
||||
if SCHEDULER and SCHEDULER.apis:
|
||||
logger.info(f"Sending {'pro ' if pro else ''}external plugins to BunkerWeb")
|
||||
ret = SCHEDULER.send_files(original_path, "/pro_plugins" if original_path.as_posix().endswith("/pro/plugins") else "/plugins")
|
||||
|
||||
if not ret:
|
||||
logger.error(f"Sending {'pro ' if pro else ''}external plugins failed, configuration will not work as expected...")
|
||||
send_nginx_external_plugins(original_path)
|
||||
|
||||
|
||||
def generate_caches():
|
||||
|
|
@ -388,7 +393,7 @@ def run_in_slave_mode():
|
|||
threads = [
|
||||
Thread(target=generate_custom_configs),
|
||||
Thread(target=generate_external_plugins),
|
||||
Thread(target=generate_external_plugins, kwargs={"original_path": PRO_PLUGINS_PATH}),
|
||||
Thread(target=generate_external_plugins, args=(PRO_PLUGINS_PATH,)),
|
||||
Thread(target=generate_caches),
|
||||
]
|
||||
|
||||
|
|
@ -613,6 +618,7 @@ if __name__ == "__main__":
|
|||
| ({"jobs": jobs} if jobs else {})
|
||||
)
|
||||
|
||||
changes = False
|
||||
if tmp_external_plugins:
|
||||
changes = {hash(dict_to_frozenset(d)) for d in tmp_external_plugins} != {hash(dict_to_frozenset(d)) for d in db_plugins}
|
||||
|
||||
|
|
@ -623,8 +629,10 @@ if __name__ == "__main__":
|
|||
logger.error(f"Couldn't save some manually added {_type} plugins to database: {err}")
|
||||
except BaseException as e:
|
||||
logger.error(f"Error while saving {_type} plugins to database: {e}")
|
||||
else:
|
||||
return send_nginx_external_plugins(plugin_path)
|
||||
|
||||
generate_external_plugins(SCHEDULER.db.get_plugins(_type=_type, with_data=True), original_path=plugin_path)
|
||||
generate_external_plugins(plugin_path)
|
||||
|
||||
threads.extend([Thread(target=check_plugin_changes, args=("external",)), Thread(target=check_plugin_changes, args=("pro",))])
|
||||
|
||||
|
|
@ -648,7 +656,7 @@ if __name__ == "__main__":
|
|||
threads.clear()
|
||||
|
||||
if changes["pro_plugins_changed"]:
|
||||
threads.append(Thread(target=generate_external_plugins, kwargs={"original_path": PRO_PLUGINS_PATH}))
|
||||
threads.append(Thread(target=generate_external_plugins, args=(PRO_PLUGINS_PATH,)))
|
||||
if changes["external_plugins_changed"]:
|
||||
threads.append(Thread(target=generate_external_plugins))
|
||||
|
||||
|
|
@ -959,12 +967,12 @@ if __name__ == "__main__":
|
|||
|
||||
if PLUGINS_NEED_GENERATION:
|
||||
CHANGES.append("external_plugins")
|
||||
generate_external_plugins(SCHEDULER.db.get_plugins(_type="external", with_data=True))
|
||||
generate_external_plugins()
|
||||
SCHEDULER.update_jobs()
|
||||
|
||||
if PRO_PLUGINS_NEED_GENERATION:
|
||||
CHANGES.append("pro_plugins")
|
||||
generate_external_plugins(SCHEDULER.db.get_plugins(_type="pro", with_data=True), original_path=PRO_PLUGINS_PATH)
|
||||
generate_external_plugins(PRO_PLUGINS_PATH)
|
||||
SCHEDULER.update_jobs()
|
||||
|
||||
if CONFIG_NEED_GENERATION:
|
||||
|
|
|
|||
Loading…
Reference in a new issue