diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ffeb28b8..34343fb95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - [BUGFIX] Fix UI using the wrong database when generating the new config when using an external database - [BUGFIX] Small fixes on linux paths creating unnecessary folders - [BUGFIX] Fix ACME renewal fails on redirection enabled Service +- [BUGFIX] Fix errors when using a server name with multiple values in web UI +- [BUGFIX] Fix error when deleting a service that have custom configs on web UI - [MISC] Updated core dependencies - [MISC] Updated self-signed job to regenerate the cert if the subject or the expiration date has changed - [MISC] Jobs that download files from urls will now remove old cached files if urls are empty diff --git a/src/bw/lua/bunkerweb/api.lua b/src/bw/lua/bunkerweb/api.lua index a6d615a08..f70e4c4f0 100644 --- a/src/bw/lua/bunkerweb/api.lua +++ b/src/bw/lua/bunkerweb/api.lua @@ -178,10 +178,10 @@ api.global.GET["^/bans$"] = function(self) local data = {} for i, k in ipairs(self.datastore:keys()) do if k:find("^bans_ip_") then - local ret, reason = self.datastore:get(k) - if not ret then + local reason, err = self.datastore:get(k) + if err then return self:response(ngx.HTTP_INTERNAL_SERVER_ERROR, "error", - "can't access " .. k .. " from datastore : " + reason) + "can't access " .. k .. " from datastore : " .. reason) end local ok, ttl = self.datastore:ttl(k) if not ok then diff --git a/src/bw/misc/asn.mmdb b/src/bw/misc/asn.mmdb index e23da59d5..13d46549f 100644 Binary files a/src/bw/misc/asn.mmdb and b/src/bw/misc/asn.mmdb differ diff --git a/src/bw/misc/country.mmdb b/src/bw/misc/country.mmdb index a126d1dfd..00bfee12a 100644 Binary files a/src/bw/misc/country.mmdb and b/src/bw/misc/country.mmdb differ diff --git a/src/common/gen/save_config.py b/src/common/gen/save_config.py index 6da89840c..32b4ff437 100644 --- a/src/common/gen/save_config.py +++ b/src/common/gen/save_config.py @@ -113,6 +113,11 @@ if __name__ == "__main__": type=str, help="The method that is used to save the config", ) + parser.add_argument( + "--no-check-changes", + action="store_true", + help="Set the changes to checked in the database", + ) args = parser.parse_args() settings_path = Path(normpath(args.settings)) @@ -361,10 +366,11 @@ if __name__ == "__main__": changes.append("instances") logger.info("Instance 127.0.0.1 successfully saved to database") - # update changes in db - ret = db.checked_changes(changes, value=True) - if ret: - logger.error(f"An error occurred when setting the changes to checked in the database : {ret}") + if not args.no_check_changes: + # update changes in db + ret = db.checked_changes(changes, value=True) + if ret: + logger.error(f"An error occurred when setting the changes to checked in the database : {ret}") except SystemExit as e: sys_exit(e.code) except: diff --git a/src/ui/gunicorn.conf.py b/src/ui/gunicorn.conf.py index 8a1618f71..977a72031 100644 --- a/src/ui/gunicorn.conf.py +++ b/src/ui/gunicorn.conf.py @@ -15,3 +15,4 @@ worker_class = "gthread" threads = 1 workers = 1 graceful_timeout = 0 +secure_scheme_headers = {} diff --git a/src/ui/main.py b/src/ui/main.py index 3475fafea..311fa0b66 100755 --- a/src/ui/main.py +++ b/src/ui/main.py @@ -232,43 +232,42 @@ def manage_bunkerweb(method: str, *args, operation: str = "reloads"): # Do the operation error = False if method == "services": - editing = operation == "edit" - service_custom_confs = glob(join(sep, "etc", "bunkerweb", "configs", "*", args[1])) + service_custom_confs = glob(join(sep, "etc", "bunkerweb", "configs", "*", args[1].split(" ")[0])) moved = False + deleted = False if operation == "new": operation, error = app.config["CONFIG"].new_service(args[0]) elif operation == "edit": - if args[1] != args[2] and service_custom_confs: + 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]}", f"{sep}{args[2]}").replace(join(sep, "etc"), join(sep, "var", "tmp")), - ) + 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]) + operation, error = app.config["CONFIG"].edit_service(args[1], args[0], check_changes=not moved) elif operation == "delete": - operation, error = app.config["CONFIG"].delete_service(args[2]) + 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) if error: app.config["TO_FLASH"].append({"content": operation, "type": "error"}) else: app.config["TO_FLASH"].append({"content": operation, "type": "success"}) - if editing and moved and args[1] != args[2] and service_custom_confs: - for tmp_service_custom_conf in glob(join(sep, "var", "tmp", "bunkerweb", "configs", "*", args[2])): - move( - tmp_service_custom_conf, - tmp_service_custom_conf.replace( - join(sep, "var", "tmp"), - join(sep, "etc"), - ), - ) - error = app.config["CONFIGFILES"].save_configs() + if moved or deleted: + changes = ["config", "custom_configs"] + error = app.config["CONFIGFILES"].save_configs(check_changes=False) if error: app.config["TO_FLASH"].append({"content": error, "type": "error"}) - rmtree(join(sep, "var", "tmp", "bunkerweb", "configs"), ignore_errors=True) + changes.pop() + + # update changes in db + ret = db.checked_changes(changes, value=True) + if ret: + app.config["TO_FLASH"].append({"content": f"An error occurred when setting the changes to checked in the database : {ret}", "type": "error"}) if method == "global_config": operation = app.config["CONFIG"].edit_global_conf(args[0]) elif method == "plugins": @@ -526,12 +525,7 @@ def services(): Thread( target=manage_bunkerweb, name="Reloading instances", - args=( - "services", - variables, - request.form.get("OLD_SERVER_NAME", "").split(" ")[0], - variables.get("SERVER_NAME", "").split(" ")[0], - ), + args=("services", variables, request.form.get("OLD_SERVER_NAME", ""), variables.get("SERVER_NAME", "")), kwargs={"operation": request.form["operation"]}, ).start() @@ -554,6 +548,7 @@ def services(): { "SERVER_NAME": { "value": service["SERVER_NAME"]["value"].split(" ")[0], + "full_value": service["SERVER_NAME"]["value"], "method": service["SERVER_NAME"]["method"], }, "USE_REVERSE_PROXY": service["USE_REVERSE_PROXY"], diff --git a/src/ui/src/Config.py b/src/ui/src/Config.py index 4c4ae9ce7..db20ae763 100644 --- a/src/ui/src/Config.py +++ b/src/ui/src/Config.py @@ -17,7 +17,7 @@ class Config: self.__settings = json_loads(Path(sep, "usr", "share", "bunkerweb", "settings.json").read_text(encoding="utf-8")) self.__db = db - def __gen_conf(self, global_conf: dict, services_conf: list[dict]) -> None: + def __gen_conf(self, global_conf: dict, services_conf: list[dict], *, check_changes: bool = True) -> None: """Generates the nginx configuration file from the given configuration Parameters @@ -62,7 +62,8 @@ class Config: str(env_file), "--method", "ui", - ], + ] + + (["--no-check-changes"] if not check_changes else []), stdin=DEVNULL, stderr=STDOUT, check=False, @@ -196,7 +197,7 @@ class Config: 0, ) - def edit_service(self, old_server_name: str, variables: dict) -> Tuple[str, int]: + def edit_service(self, old_server_name: str, variables: dict, *, check_changes: bool = True) -> Tuple[str, int]: """Edits a service Parameters @@ -231,12 +232,12 @@ class Config: if changed_server_name: for k in deepcopy(config): - if k.startswith(old_server_name): + if k.startswith(old_server_name_splitted[0]): config.pop(k) - self.__gen_conf(config, services) + self.__gen_conf(config, services, check_changes=check_changes) return ( - f"Configuration for {old_server_name.split(' ')[0]} has been edited.", + f"Configuration for {old_server_name_splitted[0]} has been edited.", 0, ) @@ -256,7 +257,7 @@ class Config: self.__gen_conf(self.get_config(methods=False) | variables, self.get_services(methods=False)) return "The global configuration has been edited." - def delete_service(self, service_name: str) -> Tuple[str, int]: + def delete_service(self, service_name: str, *, check_changes: bool = True) -> Tuple[str, int]: """Deletes a service Parameters @@ -301,5 +302,5 @@ class Config: if k in service: service.pop(k) - self.__gen_conf(new_env, new_services) + self.__gen_conf(new_env, new_services, check_changes=check_changes) return f"Configuration for {service_name} has been deleted.", 0 diff --git a/src/ui/src/ConfigFiles.py b/src/ui/src/ConfigFiles.py index a5668a5d8..f4805f855 100644 --- a/src/ui/src/ConfigFiles.py +++ b/src/ui/src/ConfigFiles.py @@ -50,7 +50,7 @@ class ConfigFiles: generate_custom_configs(custom_configs) self.__logger.info("Custom configs refreshed successfully") - def save_configs(self) -> str: + def save_configs(self, *, check_changes: bool = True) -> str: custom_configs = [] configs_path = join(sep, "etc", "bunkerweb", "configs") root_dirs = listdir(configs_path) @@ -70,7 +70,7 @@ class ConfigFiles: } ) - err = self.__db.save_custom_configs(custom_configs, "ui") + err = self.__db.save_custom_configs(custom_configs, "ui", changed=check_changes) if err: self.__logger.error(f"Could not save custom configs: {err}") return "Couldn't save custom configs to database" diff --git a/src/ui/static/js/services.js b/src/ui/static/js/services.js index bb31473c8..fbf3272af 100644 --- a/src/ui/static/js/services.js +++ b/src/ui/static/js/services.js @@ -64,7 +64,11 @@ class ServiceModal { ) { //set form info and right form const [action, serviceName] = this.getActionAndServName(e.target); - this.setForm(action, serviceName, this.formNewEdit); + const oldServName = e.target + .closest("[data-services-service]") + .querySelector("[data-old-service-name]") + .getAttribute("data-value"); + this.setForm(action, serviceName, oldServName, this.formNewEdit); //get service data and parse it //multiple type logic is launch at same time on relate class const servicesSettings = e.target @@ -87,7 +91,7 @@ class ServiceModal { ) { //set form info and right form const [action, serviceName] = this.getActionAndServName(e.target); - this.setForm(action, serviceName, this.formNewEdit); + this.setForm(action, serviceName, serviceName, this.formNewEdit); //set default value with method default this.setSettingsDefault(); //server name is unset @@ -110,7 +114,7 @@ class ServiceModal { ) { //set form info and right form const [action, serviceName] = this.getActionAndServName(e.target); - this.setForm(action, serviceName, this.formDelete); + this.setForm(action, serviceName, serviceName, this.formDelete); //show modal this.openModal(); } @@ -202,7 +206,7 @@ class ServiceModal { } } - setForm(action, serviceName, formEl) { + setForm(action, serviceName, oldServName, formEl) { this.modalTitle.textContent = `${action} ${serviceName}`; formEl.setAttribute("id", `form-${action}-${serviceName}`); const opeInp = formEl.querySelector(`input[name="operation"]`); @@ -212,8 +216,8 @@ class ServiceModal { if (action === "edit" || action === "new") { this.showNewEditForm(); const oldNameInp = formEl.querySelector(`input[name="OLD_SERVER_NAME"]`); - oldNameInp.setAttribute("value", serviceName); - oldNameInp.value = serviceName; + oldNameInp.setAttribute("value", oldServName); + oldNameInp.value = oldServName; } if (action === "delete") { diff --git a/src/ui/templates/head.html b/src/ui/templates/head.html index 90f58f9e4..d9707255d 100644 --- a/src/ui/templates/head.html +++ b/src/ui/templates/head.html @@ -19,7 +19,7 @@ - + {% if current_endpoint == "global_config" %} diff --git a/src/ui/templates/services.html b/src/ui/templates/services.html index f57db3b07..0ba989f5f 100644 --- a/src/ui/templates/services.html +++ b/src/ui/templates/services.html @@ -32,6 +32,7 @@ class="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" >
+