update services page and modes

* delete form done
* fix draft form value send
* add missing new state to some form builder
* fix store send data (now operation and mode are send)
* fix csrf token parameters name check
This commit is contained in:
Jordan Blasenhauer 2024-08-06 15:05:00 +02:00
parent adf0d4f4f2
commit 9289864808
20 changed files with 81 additions and 58 deletions

View file

@ -39,7 +39,7 @@ def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict,
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("raw",)),
"templates": get_forms(templates, plugins, settings, ("raw",), is_new),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},

View file

@ -192,13 +192,14 @@ def services_action(
"color": "delete",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : {server_name}, "operation" : "{operation}" }}""",
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "operation" : "{operation}" }}""",
},
},
)
if operation == "draft":
draft_value = "yes" if is_draft else "no"
# get reverse of current state for update
draft_value = "no" if is_draft else "yes"
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
@ -207,7 +208,7 @@ def services_action(
"color": "success",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : {server_name}, "OLD_SERVER_NAME" : {server_name}, "operation" : "edit", "IS_DRAFT" : {draft_value} }}""",
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "OLD_SERVER_NAME" : "{server_name}", "operation" : "edit", "IS_DRAFT" : "{draft_value}" }}""",
},
},
)

View file

@ -30,6 +30,14 @@ def get_forms(templates: list = [], plugins: list = [], settings: dict = {}, ren
We will run on each plugins, set template value if one, and override by the custom settings value if exists.
We will format to fit each form type (easy, advanced, raw) in case
"""
# Update SERVER_NAME to be empty if new
if is_new and "SERVER_NAME" in settings:
settings["SERVER_NAME"]["value"] = ""
if is_new and not "SERVER_NAME" in settings:
settings["SERVER_NAME"] = {"value": "", "method": "ui", "global": True}
forms = {}
for form in render_forms:
forms[form] = {}
@ -121,9 +129,6 @@ def set_raw(template: list, plugins_base: list, settings: dict, is_new: bool) ->
if val != default_val:
raw_value = val
if setting == "SERVER_NAME" and is_new:
raw_value = ""
# Add value only if exists
if raw_value:
raw_settings[setting] = raw_value
@ -384,9 +389,6 @@ def format_setting(
# Update value or set default as value
setting_value["value"] = template_settings.get(setting_name, setting_value.get("default"))
if setting_name == "SERVER_NAME" and is_new:
setting_value["value"] = ""
# Then override by service settings if not a multiple
# Case multiple, we need to keep the default value and override only each multiple group
if setting_name in settings and not "multiple" in setting_value:

View file

@ -106,7 +106,7 @@ def move_template(folder: Path, target_folder: Path):
for file in folder.rglob("index.html"):
file_html = base_html
if "global-config" in file.parts or "jobs" in file.parts or "services" in file.parts or "raw" in file.parts:
if "global-config" in file.parts or "jobs" in file.parts or "services" in file.parts or "modes" in file.parts:
file_html = base_html.replace("data_server_builder[1:-1]", "data_server_builder")
content = file.read_text()

View file

@ -6,7 +6,7 @@
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Raw mode</title>
<title>BunkerWeb | Modes</title>
</head>
<body>
<div class="hidden" data-server-global='{"username" : "admin"}'></div>

View file

@ -353,10 +353,11 @@ export const createFormStore = (storeName, formType) => {
_updateTempState();
if (!isUpdateData.value) return;
data = JSON.parse(JSON.stringify(formattedData.value));
const data = JSON.parse(JSON.stringify(formattedData.value));
data["operation"] = operation.value;
data["OLD_SERVER_NAME"] = oldServerName.value;
print(data);
data["mode"] = type.value;
useSubmitForm(data);
}
/**

View file

@ -33,7 +33,7 @@ def advanced_mode_builder(templates: list[dict], plugins: list, global_config: d
"data": {
"templates": get_forms(templates, plugins, settings, ("advanced",), is_new),
"operation": "new" if is_new else "edit",
"old_service_name": service_name if not service_name else "",
"oldServerName": service_name if service_name else "",
},
},
],

View file

@ -33,7 +33,7 @@ def easy_mode_builder(templates: list[dict], plugins: list, global_config: dict,
"data": {
"templates": get_forms(templates, plugins, settings, ("easy",), is_new),
"operation": "new" if is_new else "edit",
"old_service_name": service_name if not service_name else "",
"oldServerName": service_name if service_name else "",
},
},
],

View file

@ -32,9 +32,9 @@ def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict,
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("raw",)),
"templates": get_forms(templates, plugins, settings, ("raw",), is_new),
"operation": "new" if is_new else "edit",
"old_service_name": service_name if not service_name else "",
"oldServerName": service_name if service_name else "",
},
},
],

View file

@ -114,7 +114,7 @@ def services_builder(services):
},
]
return builder
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
def services_settings(settings: dict) -> dict:
@ -184,7 +184,7 @@ def services_action(
"color": "delete",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : {server_name}, "operation" : "{operation}" }}""",
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "operation" : "{operation}" }}""",
},
},
)
@ -199,7 +199,7 @@ def services_action(
"color": "success",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : {server_name}, "OLD_SERVER_NAME" : {server_name}, "operation" : "edit", "IS_DRAFT" : {draft_value} }}""",
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "OLD_SERVER_NAME" : "{server_name}", "operation" : "edit", "IS_DRAFT" : "{draft_value}" }}""",
},
},
)

View file

@ -30,6 +30,14 @@ def get_forms(templates: list = [], plugins: list = [], settings: dict = {}, ren
We will run on each plugins, set template value if one, and override by the custom settings value if exists.
We will format to fit each form type (easy, advanced, raw) in case
"""
# Update SERVER_NAME to be empty if new
if is_new and "SERVER_NAME" in settings:
settings["SERVER_NAME"]["value"] = ""
if is_new and not "SERVER_NAME" in settings:
settings["SERVER_NAME"] = {"value": "", "method": "ui", "global": True}
forms = {}
for form in render_forms:
forms[form] = {}
@ -121,9 +129,6 @@ def set_raw(template: list, plugins_base: list, settings: dict, is_new: bool) ->
if val != default_val:
raw_value = val
if setting == "SERVER_NAME" and is_new:
raw_value = ""
# Add value only if exists
if raw_value:
raw_settings[setting] = raw_value
@ -384,9 +389,6 @@ def format_setting(
# Update value or set default as value
setting_value["value"] = template_settings.get(setting_name, setting_value.get("default"))
if setting_name == "SERVER_NAME" and is_new:
setting_value["value"] = ""
# Then override by service settings if not a multiple
# Case multiple, we need to keep the default value and override only each multiple group
if setting_name in settings and not "multiple" in setting_value:

View file

@ -30,6 +30,7 @@
"raw": {
"default": {
"MULTISITE": "yes",
"SERVER_NAME": "app1.example.com",
"LOG_LEVEL": "info",
"API_WHITELIST_IP": "127.0.0.0/24 10.20.30.0/24",
"BUNKERWEB_INSTANCES": "bunkerweb",

View file

@ -1 +1 @@
W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogMTIsICJ0YWJsZXQiOiAxMiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRpdGxlIiwgImRhdGEiOiB7InRpdGxlIjogImFwcDEuZXhhbXBsZS5jb20iLCAidHlwZSI6ICJjb250YWluZXIiLCAibG93ZXJjYXNlIjogdHJ1ZX19LCB7InR5cGUiOiAiU3VidGl0bGUiLCAiZGF0YSI6IHsic3VidGl0bGUiOiAic2VydmljZXNfbWFuYWdlX3N1YnRpdGxlIiwgInR5cGUiOiAiY29udGFpbmVyIiwgInN1YnRpdGxlQ2xhc3MiOiAibWItNCJ9fSwgeyJ0eXBlIjogIlRlbXBsYXRlcyIsICJkYXRhIjogeyJ0ZW1wbGF0ZXMiOiB7InJhdyI6IHsiZGVmYXVsdCI6IHsiTVVMVElTSVRFIjogInllcyIsICJMT0dfTEVWRUwiOiAiaW5mbyIsICJBUElfV0hJVEVMSVNUX0lQIjogIjEyNy4wLjAuMC8yNCAxMC4yMC4zMC4wLzI0IiwgIkJVTktFUldFQl9JTlNUQU5DRVMiOiAiYnVua2Vyd2ViIiwgIlVTRV9CTEFDS0xJU1QiOiAibm8iLCAiVVNFX0JVTktFUk5FVCI6ICJubyIsICJDT1JTX0FMTE9XX09SSUdJTiI6ICJzZWxmIiwgIkNST1NTX09SSUdJTl9PUEVORVJfUE9MSUNZIjogInNhbWUtb3JpZ2luIiwgIkNST1NTX09SSUdJTl9FTUJFRERFUl9QT0xJQ1kiOiAicmVxdWlyZS1jb3JwIiwgIkNST1NTX09SSUdJTl9SRVNPVVJDRV9QT0xJQ1kiOiAic2FtZS1zaXRlIiwgIlVTRV9DTElFTlRfQ0FDSEUiOiAieWVzIiwgIlVTRV9HWklQIjogInllcyIsICJSRU1PVkVfSEVBREVSUyI6ICJTZXJ2ZXIgRXhwZWN0LUNUIFgtUG93ZXJlZC1CeSBYLUFzcE5ldC1WZXJzaW9uIFgtQXNwTmV0TXZjLVZlcnNpb24gUHVibGljLUtleS1QaW5zIiwgIktFRVBfVVBTVFJFQU1fSEVBREVSUyI6ICJDb250ZW50LVNlY3VyaXR5LVBvbGljeSBQZXJtaXNzaW9ucy1Qb2xpY3kgWC1GcmFtZS1PcHRpb25zIiwgIlNUUklDVF9UUkFOU1BPUlRfU0VDVVJJVFkiOiAibWF4LWFnZT0zMTUzNjAwMDsgaW5jbHVkZVN1YkRvbWFpbnM7IHByZWxvYWQiLCAiUEVSTUlTU0lPTlNfUE9MSUNZIjogImFjY2VsZXJvbWV0ZXI9KCksIGFtYmllbnQtbGlnaHQtc2Vuc29yPSgpLCBhdHRyaWJ1dGlvbi1yZXBvcnRpbmc9KCksIGF1dG9wbGF5PSgpLCBiYXR0ZXJ5PSgpLCBibHVldG9vdGg9KCksIGJyb3dzaW5nLXRvcGljcz0oKSwgY2FtZXJhPSgpLCBjb21wdXRlLXByZXNzdXJlPSgpLCBkaXNwbGF5LWNhcHR1cmU9KCksIGRvY3VtZW50LWRvbWFpbj0oKSwgZW5jcnlwdGVkLW1lZGlhPSgpLCBleGVjdXRpb24td2hpbGUtbm90LXJlbmRlcmVkPSgpLCBleGVjdXRpb24td2hpbGUtb3V0LW9mLXZpZXdwb3J0PSgpLCBmdWxsc2NyZWVuPSgpLCBnYW1lcGFkPSgpLCBnZW9sb2NhdGlvbj0oKSwgZ3lyb3Njb3BlPSgpLCBoaWQ9KCksIGlkZW50aXR5LWNyZWRlbnRpYWxzLWdldD0oKSwgaWRsZS1kZXRlY3Rpb249KCksIGxvY2FsLWZvbnRzPSgpLCBtYWduZXRvbWV0ZXI9KCksIG1pY3JvcGhvbmU9KCksIG1pZGk9KCksIG90cC1jcmVkZW50aWFscz0oKSwgcGF5bWVudD0oKSwgcGljdHVyZS1pbi1waWN0dXJlPSgpLCBwdWJsaWNrZXktY3JlZGVudGlhbHMtY3JlYXRlPSgpLCBwdWJsaWNrZXktY3JlZGVudGlhbHMtZ2V0PSgpLCBzY3JlZW4td2FrZS1sb2NrPSgpLCBzZXJpYWw9KCksIHNwZWFrZXItc2VsZWN0aW9uPSgpLCBzdG9yYWdlLWFjY2Vzcz0oKSwgdXNiPSgpLCB3ZWItc2hhcmU9KCksIHdpbmRvdy1tYW5hZ2VtZW50PSgpLCB4ci1zcGF0aWFsLXRyYWNraW5nPSgpIiwgIkRJU0FCTEVfREVGQVVMVF9TRVJWRVIiOiAieWVzIiwgIlNFUlZFX0ZJTEVTIjogIm5vIiwgIlNFTkRfQU5PTllNT1VTX1JFUE9SVCI6ICJubyIsICJNT0RTRUNVUklUWV9DUlNfVkVSU0lPTiI6ICI0IiwgIlVTRV9SRVZFUlNFX1BST1hZIjogInllcyIsICJSRVZFUlNFX1BST1hZX0hPU1QiOiAiaHR0cDovL2FwcDE6ODA4MCIsICJVU0VfV0hJVEVMSVNUIjogIm5vIn19fSwgIm9wZXJhdGlvbiI6ICJlZGl0IiwgIm9sZF9zZXJ2aWNlX25hbWUiOiAiIn19XX1d
W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogMTIsICJ0YWJsZXQiOiAxMiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRpdGxlIiwgImRhdGEiOiB7InRpdGxlIjogImFwcDEuZXhhbXBsZS5jb20iLCAidHlwZSI6ICJjb250YWluZXIiLCAibG93ZXJjYXNlIjogdHJ1ZX19LCB7InR5cGUiOiAiU3VidGl0bGUiLCAiZGF0YSI6IHsic3VidGl0bGUiOiAic2VydmljZXNfbWFuYWdlX3N1YnRpdGxlIiwgInR5cGUiOiAiY29udGFpbmVyIiwgInN1YnRpdGxlQ2xhc3MiOiAibWItNCJ9fSwgeyJ0eXBlIjogIlRlbXBsYXRlcyIsICJkYXRhIjogeyJ0ZW1wbGF0ZXMiOiB7InJhdyI6IHsiZGVmYXVsdCI6IHsiTVVMVElTSVRFIjogInllcyIsICJTRVJWRVJfTkFNRSI6ICJhcHAxLmV4YW1wbGUuY29tIiwgIkxPR19MRVZFTCI6ICJpbmZvIiwgIkFQSV9XSElURUxJU1RfSVAiOiAiMTI3LjAuMC4wLzI0IDEwLjIwLjMwLjAvMjQiLCAiQlVOS0VSV0VCX0lOU1RBTkNFUyI6ICJidW5rZXJ3ZWIiLCAiVVNFX0JMQUNLTElTVCI6ICJubyIsICJVU0VfQlVOS0VSTkVUIjogIm5vIiwgIkNPUlNfQUxMT1dfT1JJR0lOIjogInNlbGYiLCAiQ1JPU1NfT1JJR0lOX09QRU5FUl9QT0xJQ1kiOiAic2FtZS1vcmlnaW4iLCAiQ1JPU1NfT1JJR0lOX0VNQkVEREVSX1BPTElDWSI6ICJyZXF1aXJlLWNvcnAiLCAiQ1JPU1NfT1JJR0lOX1JFU09VUkNFX1BPTElDWSI6ICJzYW1lLXNpdGUiLCAiVVNFX0NMSUVOVF9DQUNIRSI6ICJ5ZXMiLCAiVVNFX0daSVAiOiAieWVzIiwgIlJFTU9WRV9IRUFERVJTIjogIlNlcnZlciBFeHBlY3QtQ1QgWC1Qb3dlcmVkLUJ5IFgtQXNwTmV0LVZlcnNpb24gWC1Bc3BOZXRNdmMtVmVyc2lvbiBQdWJsaWMtS2V5LVBpbnMiLCAiS0VFUF9VUFNUUkVBTV9IRUFERVJTIjogIkNvbnRlbnQtU2VjdXJpdHktUG9saWN5IFBlcm1pc3Npb25zLVBvbGljeSBYLUZyYW1lLU9wdGlvbnMiLCAiU1RSSUNUX1RSQU5TUE9SVF9TRUNVUklUWSI6ICJtYXgtYWdlPTMxNTM2MDAwOyBpbmNsdWRlU3ViRG9tYWluczsgcHJlbG9hZCIsICJQRVJNSVNTSU9OU19QT0xJQ1kiOiAiYWNjZWxlcm9tZXRlcj0oKSwgYW1iaWVudC1saWdodC1zZW5zb3I9KCksIGF0dHJpYnV0aW9uLXJlcG9ydGluZz0oKSwgYXV0b3BsYXk9KCksIGJhdHRlcnk9KCksIGJsdWV0b290aD0oKSwgYnJvd3NpbmctdG9waWNzPSgpLCBjYW1lcmE9KCksIGNvbXB1dGUtcHJlc3N1cmU9KCksIGRpc3BsYXktY2FwdHVyZT0oKSwgZG9jdW1lbnQtZG9tYWluPSgpLCBlbmNyeXB0ZWQtbWVkaWE9KCksIGV4ZWN1dGlvbi13aGlsZS1ub3QtcmVuZGVyZWQ9KCksIGV4ZWN1dGlvbi13aGlsZS1vdXQtb2Ytdmlld3BvcnQ9KCksIGZ1bGxzY3JlZW49KCksIGdhbWVwYWQ9KCksIGdlb2xvY2F0aW9uPSgpLCBneXJvc2NvcGU9KCksIGhpZD0oKSwgaWRlbnRpdHktY3JlZGVudGlhbHMtZ2V0PSgpLCBpZGxlLWRldGVjdGlvbj0oKSwgbG9jYWwtZm9udHM9KCksIG1hZ25ldG9tZXRlcj0oKSwgbWljcm9waG9uZT0oKSwgbWlkaT0oKSwgb3RwLWNyZWRlbnRpYWxzPSgpLCBwYXltZW50PSgpLCBwaWN0dXJlLWluLXBpY3R1cmU9KCksIHB1YmxpY2tleS1jcmVkZW50aWFscy1jcmVhdGU9KCksIHB1YmxpY2tleS1jcmVkZW50aWFscy1nZXQ9KCksIHNjcmVlbi13YWtlLWxvY2s9KCksIHNlcmlhbD0oKSwgc3BlYWtlci1zZWxlY3Rpb249KCksIHN0b3JhZ2UtYWNjZXNzPSgpLCB1c2I9KCksIHdlYi1zaGFyZT0oKSwgd2luZG93LW1hbmFnZW1lbnQ9KCksIHhyLXNwYXRpYWwtdHJhY2tpbmc9KCkiLCAiRElTQUJMRV9ERUZBVUxUX1NFUlZFUiI6ICJ5ZXMiLCAiU0VSVkVfRklMRVMiOiAibm8iLCAiU0VORF9BTk9OWU1PVVNfUkVQT1JUIjogIm5vIiwgIk1PRFNFQ1VSSVRZX0NSU19WRVJTSU9OIjogIjQiLCAiVVNFX1JFVkVSU0VfUFJPWFkiOiAieWVzIiwgIlJFVkVSU0VfUFJPWFlfSE9TVCI6ICJodHRwOi8vYXBwMTo4MDgwIiwgIlVTRV9XSElURUxJU1QiOiAibm8ifX19LCAib3BlcmF0aW9uIjogImVkaXQiLCAib2xkX3NlcnZpY2VfbmFtZSI6ICIifX1dfV0=

View file

@ -1147,8 +1147,8 @@ def instances():
def get_service_data(page_name: str):
verify_data_in_form(
data={"csrf-token": None},
err_message=f"Missing csrf-token parameter on /{page_name}.",
data={"csrf_token": None},
err_message=f"Missing csrf_token parameter on /{page_name}.",
redirect_url="services",
)
@ -1168,13 +1168,18 @@ def get_service_data(page_name: str):
# Check variables
variables = deepcopy(request.form.to_dict())
print(variables, flush=True)
mode = None
try:
mode = variables.pop("mode")
except:
pass
del variables["csrf_token"]
operation = variables.pop("operation")
# Delete custom client variables
try:
variables.pop("SECURITY_LEVEL", None)
variables.pop("mode", None)
except:
pass
@ -1240,10 +1245,10 @@ def get_service_data(page_name: str):
del variables[variable]
variables = app.bw_config.check_variables(variables, config)
return config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged
return config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, mode
def update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, redirect_name):
def update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged):
if request.form["operation"] == "edit":
if is_draft_unchanged and len(variables) == 1 and "SERVER_NAME" in variables and server_name == old_server_name:
return handle_error("The service was not edited because no values were changed.", "services", True)
@ -1300,7 +1305,7 @@ def update_service(config, variables, format_configs, server_name, old_server_na
elif request.form["operation"] == "delete":
message = f"Deleting {'draft ' if was_draft and is_draft else ''}service {request.form.get('SERVER_NAME', '').split(' ')[0]}"
return redirect(url_for("loading", next=url_for(redirect_name, service_name=[server_name]), message=message))
return message
@app.route("/modes", methods=["GET", "POST"])
@ -1310,8 +1315,16 @@ def services_modes():
if DB.readonly:
return handle_error("Database is in read-only mode", "services")
config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged = get_service_data("modes")
update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, "raw-mode")
config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, mode = get_service_data("modes")
message = update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged)
print(message, flush=True)
print("mode", mode, "service name", server_name, flush=True)
# TODO: redirect to /mode?service_name=my_service&mode=my_mode
# Following is not working :
# return redirect(url_for("loading", next=url_for("modes", mode=mode, service_name=server_name), message=message))
# or
# return redirect(url_for("loading", next=url_for(f"modes?service_name={server_name}&mode={mode}"), message=message))
return redirect(url_for("loading", next=url_for(request.endpoint), message=message))
if not request.args.get("mode"):
return handle_error("Mode type is missing to access /modes.", "services")
@ -1353,8 +1366,11 @@ def services():
if DB.readonly:
return handle_error("Database is in read-only mode", "services")
config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged = get_service_data("services")
update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, "services")
config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged, mode = get_service_data("services")
message = update_service(config, variables, format_configs, server_name, old_server_name, operation, is_draft, was_draft, is_draft_unchanged)
return redirect(url_for("loading", next=url_for("services"), message=message))
# Display services
services = []

View file

@ -7,10 +7,10 @@
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Global config</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/global_config-CZ0G5nSa.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-BydAGXrY.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Templates-DP-xygY2.js">
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/global_config-Bbd-rVb6.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-D8ODdwjg.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Templates--9yerr1U.js">
<link rel="stylesheet" crossorigin href="assets/ButtonGroup-D2kv0NCW.css">
</head>

View file

@ -7,8 +7,8 @@
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Home</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/home-NrasATfu.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/home-ICmkvFmx.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
</head>
<body>

View file

@ -7,9 +7,9 @@
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Instances</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/instances-DxqGoKEC.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-BydAGXrY.js">
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/instances-CzjX3yAI.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-D8ODdwjg.js">
<link rel="stylesheet" crossorigin href="assets/ButtonGroup-D2kv0NCW.css">
</head>

View file

@ -7,9 +7,9 @@
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Jobs</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/jobs-DeJBFKqF.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-BydAGXrY.js">
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/jobs-BV_6EZGr.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-D8ODdwjg.js">
<link rel="stylesheet" crossorigin href="assets/ButtonGroup-D2kv0NCW.css">
</head>

View file

@ -6,11 +6,11 @@
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Raw mode</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/modes-5pzf6B6M.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-BydAGXrY.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Templates-DP-xygY2.js">
<title>BunkerWeb | Modes</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/modes-BwlKIq_9.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-D8ODdwjg.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Templates--9yerr1U.js">
<link rel="stylesheet" crossorigin href="assets/ButtonGroup-D2kv0NCW.css">
</head>

View file

@ -7,9 +7,9 @@
<link rel="stylesheet" href="css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Services</title>
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/services-DZJyCK1K.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-BIcESj1V.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-BydAGXrY.js">
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/services-DCDrkWrE.js"></script>
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-Bzn9Bwnl.js">
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/ButtonGroup-D8ODdwjg.js">
<link rel="stylesheet" crossorigin href="assets/ButtonGroup-D2kv0NCW.css">
</head>