mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
enhance builder + pages + simplify raw mode
* update pages header to fit content * add typing to builder utils * simplify raw mode json to key=value format + fix value rendered * update vite config * update builder to logic to work with global config json * update i18n * update main.py global config route
This commit is contained in:
parent
d1cafdc3c0
commit
ed9b9ba27e
17 changed files with 205 additions and 390 deletions
|
|
@ -1,9 +1,12 @@
|
|||
import base64
|
||||
import json
|
||||
import copy
|
||||
from typing import Union
|
||||
|
||||
|
||||
def stat_widget(link, containerColums, title, subtitle, subtitle_color, stat, icon_name):
|
||||
def stat_widget(
|
||||
link: str, containerColums: dict, title: Union[str, int], subtitle: Union[str, int], subtitle_color: str, stat: Union[str, int], icon_name: str
|
||||
) -> dict:
|
||||
"""Return a valid format to render a Stat widget"""
|
||||
return {
|
||||
"type": "card",
|
||||
|
|
@ -24,7 +27,7 @@ def stat_widget(link, containerColums, title, subtitle, subtitle_color, stat, ic
|
|||
}
|
||||
|
||||
|
||||
def instance_widget(containerColumns, pairs, status, title, buttons):
|
||||
def instance_widget(containerColumns: dict, pairs: list[dict], status: str, title: Union[str, int], buttons: list[dict]) -> dict:
|
||||
"""Return a valid format to render an Instance widget"""
|
||||
return {
|
||||
"type": "card",
|
||||
|
|
@ -43,7 +46,7 @@ def instance_widget(containerColumns, pairs, status, title, buttons):
|
|||
}
|
||||
|
||||
|
||||
def home_builder(data):
|
||||
def home_builder(data: dict) -> str:
|
||||
"""
|
||||
It returns the needed format from data to render the home page in JSON format for the Vue.js builder
|
||||
"""
|
||||
|
|
@ -126,7 +129,7 @@ def home_builder(data):
|
|||
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
|
||||
|
||||
|
||||
def instances_builder(instances: list):
|
||||
def instances_builder(instances: list) -> str:
|
||||
"""
|
||||
It returns the needed format from data to render the instances page in JSON format for the Vue.js builder
|
||||
"""
|
||||
|
|
@ -172,23 +175,30 @@ def instances_builder(instances: list):
|
|||
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
|
||||
|
||||
|
||||
def get_forms(templates=[], plugins=[], settings={}):
|
||||
def get_forms(templates: list = [], plugins: list = [], settings: dict = {}, render_forms: tuple = ("advanced", "easy", "raw")) -> dict:
|
||||
"""
|
||||
Will generate every needed form using templates, plugins and settings.
|
||||
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).
|
||||
We will format to fit each form type (easy, advanced, raw) in case
|
||||
"""
|
||||
forms = {"advanced": {}, "easy": {}, "raw": {}}
|
||||
forms = {}
|
||||
for form in render_forms:
|
||||
forms[form] = {}
|
||||
|
||||
for template in templates:
|
||||
forms["advanced"][template.get("name")] = set_advanced(template, plugins, settings)
|
||||
forms["raw"][template.get("name")] = set_raw(template, plugins, settings)
|
||||
forms["easy"][template.get("name")] = set_easy(template, plugins, settings)
|
||||
if "advanced" in forms:
|
||||
forms["advanced"][template.get("name")] = set_advanced(template, plugins, settings)
|
||||
|
||||
if "raw" in forms:
|
||||
forms["raw"][template.get("name")] = set_raw(template, plugins, settings)
|
||||
|
||||
if "easy" in forms:
|
||||
forms["easy"][template.get("name")] = set_easy(template, plugins, settings)
|
||||
|
||||
return forms
|
||||
|
||||
|
||||
def set_easy(template, plugins_base, settings):
|
||||
def set_easy(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Prepare the easy form based on the template and plugins data.
|
||||
We need to loop on each steps and prepare settings and configs for each step.
|
||||
|
|
@ -234,7 +244,7 @@ def set_easy(template, plugins_base, settings):
|
|||
return steps
|
||||
|
||||
|
||||
def set_raw(template, plugins_base, settings):
|
||||
def set_raw(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Set the raw form based on the template and plugins data.
|
||||
It consists of keeping only the value or default value for each plugin settings.
|
||||
|
|
@ -259,7 +269,13 @@ def set_raw(template, plugins_base, settings):
|
|||
|
||||
# Then override by service settings
|
||||
if setting in settings:
|
||||
raw_value = settings[setting].get("value", value.get("value", value.get("default")))
|
||||
val = settings[setting].get("value", value.get("value"))
|
||||
|
||||
# Check if value is same as default
|
||||
# If case, we don't need to add it
|
||||
default_val = value.get("default")
|
||||
if val == default_val:
|
||||
raw_value = None
|
||||
|
||||
# Add value only if exists
|
||||
if raw_value:
|
||||
|
|
@ -268,7 +284,7 @@ def set_raw(template, plugins_base, settings):
|
|||
return raw_settings
|
||||
|
||||
|
||||
def set_advanced(template, plugins_base, settings):
|
||||
def set_advanced(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Set the advanced form based on the template and plugins data.
|
||||
It consists of formatting each plugin settings to be used in the advanced form.
|
||||
|
|
@ -413,7 +429,7 @@ def get_multiple_from_settings(settings, multiples):
|
|||
return multiple_settings
|
||||
|
||||
|
||||
def set_multiples(template, format_plugins, service_settings):
|
||||
def set_multiples(template, format_plugins, settings):
|
||||
"""
|
||||
Set the multiples settings for each plugin.
|
||||
"""
|
||||
|
|
@ -452,7 +468,7 @@ def set_multiples(template, format_plugins, service_settings):
|
|||
# Get all settings from template that are multiples
|
||||
template_multiples = get_multiple_from_template(template, multiples)
|
||||
# Get all settings from service settings / global config that are multiples
|
||||
service_multiples = get_multiple_from_settings(service_settings, multiples)
|
||||
service_multiples = get_multiple_from_settings(settings, multiples)
|
||||
# Get service multiples if at least one, else use template multiples
|
||||
plugin["multiples"] = service_multiples if len(service_multiples) else template_multiples
|
||||
|
||||
|
|
@ -460,13 +476,13 @@ def set_multiples(template, format_plugins, service_settings):
|
|||
|
||||
|
||||
def format_setting(
|
||||
setting_name,
|
||||
setting_value,
|
||||
total_settings,
|
||||
loop_id,
|
||||
template_settings,
|
||||
service_settings,
|
||||
):
|
||||
setting_name: str,
|
||||
setting_value: Union[str, int],
|
||||
total_settings: Union[str, int],
|
||||
loop_id: Union[str, int],
|
||||
template_settings: dict,
|
||||
settings: dict,
|
||||
) -> dict:
|
||||
"""
|
||||
Format a setting in order to be used with form builder.
|
||||
This will only set value for none multiple settings.
|
||||
|
|
@ -511,18 +527,18 @@ def format_setting(
|
|||
|
||||
# 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 service_settings and not "multiple" in setting_value:
|
||||
setting_value["value"] = service_settings[setting_name].get("value", setting_value.get("value", setting_value.get("default")))
|
||||
setting_value["method"] = service_settings[setting_name].get("method", "ui")
|
||||
if setting_name in settings and not "multiple" in setting_value:
|
||||
setting_value["value"] = settings[setting_name].get("value", setting_value.get("value", setting_value.get("default")))
|
||||
setting_value["method"] = settings[setting_name].get("method", "ui")
|
||||
|
||||
# Then override by service settings
|
||||
if setting_name in service_settings:
|
||||
setting_value["disabled"] = False if service_settings[setting_name].get("method", "ui") in ("ui", "default", "manual") else True
|
||||
if setting_name in settings:
|
||||
setting_value["disabled"] = False if settings[setting_name].get("method", "ui") in ("ui", "default", "manual") else True
|
||||
|
||||
# Prepare popover checking "help", "context"
|
||||
popovers = []
|
||||
|
||||
if (setting_value.get("disabled", False)) and service_settings[setting_name].get("method", "ui") not in ("ui", "default", "manual"):
|
||||
if (setting_value.get("disabled", False)) and settings[setting_name].get("method", "ui") not in ("ui", "default", "manual"):
|
||||
popovers.append(
|
||||
{
|
||||
"iconName": "trespass",
|
||||
|
|
@ -550,7 +566,7 @@ def format_setting(
|
|||
return setting_value
|
||||
|
||||
|
||||
def global_config_builder(plugins, settings):
|
||||
def global_config_builder(plugins: list, settings: dict) -> str:
|
||||
"""Render forms with global config data.
|
||||
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
|
||||
"""
|
||||
|
|
@ -580,11 +596,10 @@ def global_config_builder(plugins, settings):
|
|||
{
|
||||
"type": "Templates",
|
||||
"data": {
|
||||
"templates": get_forms(templates, plugins, settings),
|
||||
"templates": get_forms(templates, plugins, settings, ("advanced", "raw")),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
|
||||
|
|
|
|||
|
|
@ -67,7 +67,9 @@ def create_base_dirs():
|
|||
def move_template(folder, target_folder):
|
||||
"""For the define folder, loop on each files and move them to the target folder with some modification (replace relative path to absolute path for example)"""
|
||||
|
||||
base_html = """
|
||||
async def move_template_file(root, file, target_folder):
|
||||
"""Move the template file to the target folder. This will replace relative path on file to absolute path to work with flask static"""
|
||||
base_html = """
|
||||
<body>
|
||||
{% set data_server_flash = [] %}
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
|
|
@ -83,8 +85,9 @@ def move_template(folder, target_folder):
|
|||
</body>
|
||||
</html>"""
|
||||
|
||||
async def move_template_file(root, file, target_folder, base_html):
|
||||
"""Move the template file to the target folder. This will replace relative path on file to absolute path to work with flask static"""
|
||||
if "global-config" in root:
|
||||
base_html = base_html.replace("data_server_builder[1:-1]", "data_server_builder")
|
||||
|
||||
file_path = os.path.join(root, file)
|
||||
|
||||
def format_template(m):
|
||||
|
|
@ -115,7 +118,7 @@ def move_template(folder, target_folder):
|
|||
# I want to get all subfollder of a folder
|
||||
for root, dirs, files in os.walk(folder):
|
||||
for file in files:
|
||||
asyncio.run(move_template_file(root, file, target_folder, base_html))
|
||||
asyncio.run(move_template_file(root, file, target_folder))
|
||||
|
||||
|
||||
def move_statics(folder, target_folder):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { defineProps, reactive, onMounted, computed } from "vue";
|
||||
import { defineProps, reactive, onMounted, computed, onBeforeMount } from "vue";
|
||||
import Container from "@components/Widget/Container.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
import Subtitle from "@components/Widget/Subtitle.vue";
|
||||
|
|
@ -44,39 +44,11 @@ const props = defineProps({
|
|||
});
|
||||
|
||||
const data = reactive({
|
||||
str: JSON.stringify(props.template),
|
||||
// Data on creation of editor
|
||||
entry: computed(() => {
|
||||
let dataStr = data.str;
|
||||
// Remove first and last curly brackets
|
||||
dataStr = dataStr.slice(1, -1);
|
||||
// Remove all '\"' from stringified JSON
|
||||
dataStr = dataStr.replace(/\\"/g, '"');
|
||||
// Remove all newlines inside values
|
||||
dataStr = dataStr.replace(/\n/g, "");
|
||||
// Add new line only at the end of each key value
|
||||
dataStr = dataStr.replace(/",/g, "\n");
|
||||
|
||||
const lines = dataStr.split("\n");
|
||||
dataStr = lines.map((line) => {
|
||||
// Get index of the first colon
|
||||
const index = line.indexOf(":");
|
||||
// Update colon by equal sign and remove quotes
|
||||
return line.slice(1, index - 1) + "=" + line.slice(index + 2);
|
||||
});
|
||||
dataStr = dataStr.join("\n");
|
||||
// Remove first char if it is a quote
|
||||
dataStr = dataStr[0] === '"' ? dataStr.slice(1) : dataStr;
|
||||
// Remove last char if it is a quote
|
||||
dataStr = dataStr.slice(-1) === '"' ? dataStr.slice(0, -1) : dataStr;
|
||||
|
||||
return dataStr;
|
||||
}),
|
||||
str: "",
|
||||
// Data retrieve from editor after creation
|
||||
inp: "",
|
||||
isValid: computed(() => {
|
||||
// Transform to a possible valid JSON
|
||||
let dataToCheck = data.inp || data.entry;
|
||||
let dataToCheck = data.str;
|
||||
// Replace quotes "" with quotes ''
|
||||
dataToCheck = dataToCheck.replace(/"/g, "'");
|
||||
|
||||
|
|
@ -111,8 +83,35 @@ const data = reactive({
|
|||
}),
|
||||
});
|
||||
|
||||
function json2raw(json) {
|
||||
let dataStr = JSON.stringify(json);
|
||||
// Remove first and last curly brackets
|
||||
dataStr = dataStr.slice(1, -1);
|
||||
// Remove all '\"' from stringified JSON
|
||||
dataStr = dataStr.replace(/\\"/g, '"');
|
||||
// Remove all newlines inside values
|
||||
dataStr = dataStr.replace(/\n/g, "");
|
||||
// Add new line only at the end of each key value
|
||||
dataStr = dataStr.replace(/",/g, "\n");
|
||||
|
||||
const lines = dataStr.split("\n");
|
||||
dataStr = lines.map((line) => {
|
||||
// Get index of the first colon
|
||||
const index = line.indexOf(":");
|
||||
// Update colon by equal sign and remove quotes
|
||||
return line.slice(1, index - 1) + "=" + line.slice(index + 2);
|
||||
});
|
||||
dataStr = dataStr.join("\n");
|
||||
// Remove first char if it is a quote
|
||||
dataStr = dataStr[0] === '"' ? dataStr.slice(1) : dataStr;
|
||||
// Remove last char if it is a quote
|
||||
dataStr = dataStr.slice(-1) === '"' ? dataStr.slice(0, -1) : dataStr;
|
||||
|
||||
return dataStr;
|
||||
}
|
||||
|
||||
const editorData = {
|
||||
value: data.inp || data.entry,
|
||||
value: data.str,
|
||||
name: `raw-editor-${uuidv4()}`,
|
||||
label: `raw-editor-${uuidv4()}`,
|
||||
hideLabel: true,
|
||||
|
|
@ -127,6 +126,10 @@ const buttonSave = {
|
|||
size: "normal",
|
||||
containerClass: "flex justify-center",
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
data.str = json2raw(props.template);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -142,7 +145,7 @@ const buttonSave = {
|
|||
<Subtitle type="card" :subtitle="'dashboard_raw_mode_subtitle'" />
|
||||
|
||||
<Container class="form-raw-editor-container layout-settings">
|
||||
<Editor @inp="(v) => (data.inp = v)" v-bind="editorData" />
|
||||
<Editor @inp="(v) => (data.str = v)" v-bind="editorData" />
|
||||
</Container>
|
||||
<Button :disabled="data.isValid ? false : true" v-bind="buttonSave" />
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@
|
|||
"inp_input_error_taken": "value already taken",
|
||||
"inp_popover_multisite": "This setting is multisite.",
|
||||
"inp_popover_global": "This setting is global.",
|
||||
"inp_popover_method_disabled": "This setting method (scheduler, autoconf...) unable value change.",
|
||||
"inp_popover_method_disabled": "The setting method disabled any change.",
|
||||
"inp_combobox": "Combobox input for relate select radio group.",
|
||||
"inp_select_dropdown_button_desc": "Toggle hide/show radio group (dropdown) to change value.",
|
||||
"inp_select_dropdown_desc": "Radio group (dropdown) to change value.",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount } from "vue";
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderGlobalConfig from "@components/Builder/GlobalConfig.vue";
|
||||
|
||||
|
|
@ -23,6 +24,10 @@ onBeforeMount(() => {
|
|||
: {};
|
||||
globalConfig.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -6,16 +6,18 @@
|
|||
<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 | DASHBOARD</title>
|
||||
<title>BunkerWeb | Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="hidden" data-server-global='{"username" : "admin"}'></div>
|
||||
<div class="hidden"
|
||||
data-server-flash='[{"type" : "success", "title" : "success", "message" : "Success feedback"}, {"type" : "error", "title" : "error", "message" : "Error feedback"}, {"type" : "warning", "title" : "warning", "message" : "Warning feedback"}, {"type" : "info", "title" : "info", "message" : "Info feedback"}]'>
|
||||
</div>
|
||||
<div class="hidden"
|
||||
data-server-builder='W3sidHlwZSI6ICJjYXJkIiwgImxpbmsiOiAiaHR0cHM6Ly9wYW5lbC5idW5rZXJ3ZWIuaW8vP3V0bV9jYW1wYWlnbj1zZWxmJnV0bV9zb3VyY2U9dWkjcHJvIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNCwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJTdGF0IiwgImRhdGEiOiB7InRpdGxlIjogImhvbWVfdmVyc2lvbiIsICJzdWJ0aXRsZSI6ICJob21lX3VwZ3JhZGVfdG9fcHJvIiwgInN1YnRpdGxlQ29sb3IiOiAid2FybmluZyIsICJzdGF0IjogImhvbWVfZnJlZSIsICJpY29uTmFtZSI6ICJrZXkifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICJodHRwczovL2dpdGh1Yi5jb20vYnVua2VyaXR5L2J1bmtlcndlYiIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX3ZlcnNpb25fbnVtYmVyIiwgInN1YnRpdGxlIjogImhvbWVfdXBkYXRlX2F2YWlsYWJsZSIsICJzdWJ0aXRsZUNvbG9yIjogIndhcm5pbmciLCAic3RhdCI6ICIxLjUuOCIsICJpY29uTmFtZSI6ICJ3aXJlIn19XX0sIHsidHlwZSI6ICJjYXJkIiwgImxpbmsiOiAiL2luc3RhbmNlcyIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX2luc3RhbmNlcyIsICJzdWJ0aXRsZSI6ICJob21lX3RvdGFsX251bWJlciIsICJzdWJ0aXRsZUNvbG9yIjogImluZm8iLCAic3RhdCI6IDEsICJpY29uTmFtZSI6ICJib3gifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICIvc2VydmljZXMiLCAiY29udGFpbmVyQ29sdW1ucyI6IHsicGMiOiA0LCAidGFibGV0IjogNiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlN0YXQiLCAiZGF0YSI6IHsidGl0bGUiOiAiaG9tZV9zZXJ2aWNlcyIsICJzdWJ0aXRsZSI6ICJob21lX2FsbF9tZXRob2RzX2luY2x1ZGVkIiwgInN1YnRpdGxlQ29sb3IiOiAiaW5mbyIsICJzdGF0IjogMiwgImljb25OYW1lIjogImRpc2sifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICIvcGx1Z2lucyIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX3BsdWdpbnMiLCAic3VidGl0bGUiOiAiaG9tZV9ub19lcnJvciIsICJzdWJ0aXRsZUNvbG9yIjogInN1Y2Nlc3MiLCAic3RhdCI6ICI0MiIsICJpY29uTmFtZSI6ICJwdXp6bGUifX1dfV0'>
|
||||
</div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-flash='[{"type" : "success", "title" : "success", "message" : "Success feedback"}, {"type" : "error", "title" : "error", "message" : "Error feedback"}, {"type" : "warning", "title" : "warning", "message" : "Warning feedback"}, {"type" : "info", "title" : "info", "message" : "Info feedback"}]'
|
||||
></div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-builder="W3sidHlwZSI6ICJjYXJkIiwgImxpbmsiOiAiaHR0cHM6Ly9wYW5lbC5idW5rZXJ3ZWIuaW8vP3V0bV9jYW1wYWlnbj1zZWxmJnV0bV9zb3VyY2U9dWkjcHJvIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNCwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJTdGF0IiwgImRhdGEiOiB7InRpdGxlIjogImhvbWVfdmVyc2lvbiIsICJzdWJ0aXRsZSI6ICJob21lX3VwZ3JhZGVfdG9fcHJvIiwgInN1YnRpdGxlQ29sb3IiOiAid2FybmluZyIsICJzdGF0IjogImhvbWVfZnJlZSIsICJpY29uTmFtZSI6ICJrZXkifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICJodHRwczovL2dpdGh1Yi5jb20vYnVua2VyaXR5L2J1bmtlcndlYiIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX3ZlcnNpb25fbnVtYmVyIiwgInN1YnRpdGxlIjogImhvbWVfdXBkYXRlX2F2YWlsYWJsZSIsICJzdWJ0aXRsZUNvbG9yIjogIndhcm5pbmciLCAic3RhdCI6ICIxLjUuOCIsICJpY29uTmFtZSI6ICJ3aXJlIn19XX0sIHsidHlwZSI6ICJjYXJkIiwgImxpbmsiOiAiL2luc3RhbmNlcyIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX2luc3RhbmNlcyIsICJzdWJ0aXRsZSI6ICJob21lX3RvdGFsX251bWJlciIsICJzdWJ0aXRsZUNvbG9yIjogImluZm8iLCAic3RhdCI6IDEsICJpY29uTmFtZSI6ICJib3gifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICIvc2VydmljZXMiLCAiY29udGFpbmVyQ29sdW1ucyI6IHsicGMiOiA0LCAidGFibGV0IjogNiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlN0YXQiLCAiZGF0YSI6IHsidGl0bGUiOiAiaG9tZV9zZXJ2aWNlcyIsICJzdWJ0aXRsZSI6ICJob21lX2FsbF9tZXRob2RzX2luY2x1ZGVkIiwgInN1YnRpdGxlQ29sb3IiOiAiaW5mbyIsICJzdGF0IjogMiwgImljb25OYW1lIjogImRpc2sifX1dfSwgeyJ0eXBlIjogImNhcmQiLCAibGluayI6ICIvcGx1Z2lucyIsICJjb250YWluZXJDb2x1bW5zIjogeyJwYyI6IDQsICJ0YWJsZXQiOiA2LCAibW9iaWxlIjogMTJ9LCAid2lkZ2V0cyI6IFt7InR5cGUiOiAiU3RhdCIsICJkYXRhIjogeyJ0aXRsZSI6ICJob21lX3BsdWdpbnMiLCAic3VidGl0bGUiOiAiaG9tZV9ub19lcnJvciIsICJzdWJ0aXRsZUNvbG9yIjogInN1Y2Nlc3MiLCAic3RhdCI6ICI0MiIsICJpY29uTmFtZSI6ICJwdXp6bGUifX1dfV0"
|
||||
></div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="home.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -6,16 +6,18 @@
|
|||
<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 | DASHBOARD</title>
|
||||
<title>BunkerWeb | Instances</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="hidden" data-server-global='{"username" : "admin"}'></div>
|
||||
<div class="hidden"
|
||||
data-server-flash='[{"type" : "success", "title" : "title", "message" : "Success feedback"}, {"type" : "error", "title" : "title", "message" : "Error feedback"}, {"type" : "warning", "title" : "title", "message" : "Warning feedback"}, {"type" : "info", "title" : "title", "message" : "Info feedback"}]'>
|
||||
</div>
|
||||
<div class="hidden"
|
||||
data-server-builder='W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNiwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJJbnN0YW5jZSIsICJkYXRhIjogeyJwYWlycyI6IFt7ImtleSI6ICJpbnN0YW5jZXNfaG9zdG5hbWUiLCAidmFsdWUiOiAiYnVua2Vyd2ViIn0sIHsia2V5IjogImluc3RhbmNlc190eXBlIiwgInZhbHVlIjogIm1hbnVhbCJ9LCB7ImtleSI6ICJpbnN0YW5jZXNfc3RhdHVzIiwgInZhbHVlIjogImluc3RhbmNlc19hY3RpdmUifV0sICJzdGF0dXMiOiAic3VjY2VzcyIsICJ0aXRsZSI6ICJidW5rZXJ3ZWIiLCAiYnV0dG9ucyI6IFt7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJyZWxvYWRcIiB9In0sICJ0ZXh0IjogImFjdGlvbl9yZWxvYWQiLCAiY29sb3IiOiAid2FybmluZyJ9LCB7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJzdG9wXCIgfSJ9LCAidGV4dCI6ICJhY3Rpb25fc3RvcCIsICJjb2xvciI6ICJlcnJvciJ9XX19XX0sIHsidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNiwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJJbnN0YW5jZSIsICJkYXRhIjogeyJwYWlycyI6IFt7ImtleSI6ICJpbnN0YW5jZXNfaG9zdG5hbWUiLCAidmFsdWUiOiAiYnVua2Vyd2ViIn0sIHsia2V5IjogImluc3RhbmNlc190eXBlIiwgInZhbHVlIjogIm1hbnVhbCJ9LCB7ImtleSI6ICJpbnN0YW5jZXNfc3RhdHVzIiwgInZhbHVlIjogImluc3RhbmNlc19hY3RpdmUifV0sICJzdGF0dXMiOiAic3VjY2VzcyIsICJ0aXRsZSI6ICJidW5rZXJ3ZWIiLCAiYnV0dG9ucyI6IFt7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJyZWxvYWRcIiB9In0sICJ0ZXh0IjogImFjdGlvbl9yZWxvYWQiLCAiY29sb3IiOiAid2FybmluZyJ9LCB7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJzdG9wXCIgfSJ9LCAidGV4dCI6ICJhY3Rpb25fc3RvcCIsICJjb2xvciI6ICJlcnJvciJ9XX19XX1d'>
|
||||
</div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-flash='[{"type" : "success", "title" : "title", "message" : "Success feedback"}, {"type" : "error", "title" : "title", "message" : "Error feedback"}, {"type" : "warning", "title" : "title", "message" : "Warning feedback"}, {"type" : "info", "title" : "title", "message" : "Info feedback"}]'
|
||||
></div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-builder="W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNiwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJJbnN0YW5jZSIsICJkYXRhIjogeyJwYWlycyI6IFt7ImtleSI6ICJpbnN0YW5jZXNfaG9zdG5hbWUiLCAidmFsdWUiOiAiYnVua2Vyd2ViIn0sIHsia2V5IjogImluc3RhbmNlc190eXBlIiwgInZhbHVlIjogIm1hbnVhbCJ9LCB7ImtleSI6ICJpbnN0YW5jZXNfc3RhdHVzIiwgInZhbHVlIjogImluc3RhbmNlc19hY3RpdmUifV0sICJzdGF0dXMiOiAic3VjY2VzcyIsICJ0aXRsZSI6ICJidW5rZXJ3ZWIiLCAiYnV0dG9ucyI6IFt7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJyZWxvYWRcIiB9In0sICJ0ZXh0IjogImFjdGlvbl9yZWxvYWQiLCAiY29sb3IiOiAid2FybmluZyJ9LCB7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJzdG9wXCIgfSJ9LCAidGV4dCI6ICJhY3Rpb25fc3RvcCIsICJjb2xvciI6ICJlcnJvciJ9XX19XX0sIHsidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogNiwgInRhYmxldCI6IDYsICJtb2JpbGUiOiAxMn0sICJ3aWRnZXRzIjogW3sidHlwZSI6ICJJbnN0YW5jZSIsICJkYXRhIjogeyJwYWlycyI6IFt7ImtleSI6ICJpbnN0YW5jZXNfaG9zdG5hbWUiLCAidmFsdWUiOiAiYnVua2Vyd2ViIn0sIHsia2V5IjogImluc3RhbmNlc190eXBlIiwgInZhbHVlIjogIm1hbnVhbCJ9LCB7ImtleSI6ICJpbnN0YW5jZXNfc3RhdHVzIiwgInZhbHVlIjogImluc3RhbmNlc19hY3RpdmUifV0sICJzdGF0dXMiOiAic3VjY2VzcyIsICJ0aXRsZSI6ICJidW5rZXJ3ZWIiLCAiYnV0dG9ucyI6IFt7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJyZWxvYWRcIiB9In0sICJ0ZXh0IjogImFjdGlvbl9yZWxvYWQiLCAiY29sb3IiOiAid2FybmluZyJ9LCB7ImF0dHJzIjogeyJkYXRhLXN1Ym1pdC1mb3JtIjogIntcIklOU1RBTkNFX0lEXCIgOiBcImJ1bmtlcndlYlwiLCBcIm9wZXJhdGlvblwiIDogXCJzdG9wXCIgfSJ9LCAidGV4dCI6ICJhY3Rpb25fc3RvcCIsICJjb2xvciI6ICJlcnJvciJ9XX19XX1d"
|
||||
></div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="instances.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -9697,195 +9697,8 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"easy": {
|
||||
"default": []
|
||||
},
|
||||
"raw": {
|
||||
"default": {
|
||||
"IS_LOADING": "no",
|
||||
"NGINX_PREFIX": "/etc/nginx/",
|
||||
"HTTP_PORT": "8080",
|
||||
"HTTPS_PORT": "8443",
|
||||
"SERVER_NAME": "app1.example.com www.example.com",
|
||||
"WORKER_PROCESSES": "auto",
|
||||
"WORKER_RLIMIT_NOFILE": "2048",
|
||||
"WORKER_CONNECTIONS": "1024",
|
||||
"LOG_FORMAT": "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\"",
|
||||
"DNS_RESOLVERS": "127.0.0.11",
|
||||
"DATASTORE_MEMORY_SIZE": "64m",
|
||||
"CACHESTORE_MEMORY_SIZE": "64m",
|
||||
"CACHESTORE_IPC_MEMORY_SIZE": "16m",
|
||||
"CACHESTORE_MISS_MEMORY_SIZE": "16m",
|
||||
"CACHESTORE_LOCKS_MEMORY_SIZE": "16m",
|
||||
"USE_API": "yes",
|
||||
"API_HTTP_PORT": "5000",
|
||||
"API_LISTEN_IP": "0.0.0.0",
|
||||
"API_SERVER_NAME": "bwapi",
|
||||
"AUTOCONF_MODE": "no",
|
||||
"SWARM_MODE": "no",
|
||||
"KUBERNETES_MODE": "no",
|
||||
"SERVER_TYPE": "http",
|
||||
"LISTEN_STREAM": "yes",
|
||||
"LISTEN_STREAM_PORT": "1337",
|
||||
"LISTEN_STREAM_PORT_SSL": "4242",
|
||||
"USE_UDP": "no",
|
||||
"USE_IPV6": "no",
|
||||
"IS_DRAFT": "no",
|
||||
"TIMERS_LOG_LEVEL": "debug",
|
||||
"USE_ANTIBOT": "no",
|
||||
"ANTIBOT_URI": "/challenge",
|
||||
"ANTIBOT_TIME_RESOLVE": "60",
|
||||
"ANTIBOT_TIME_VALID": "86400",
|
||||
"ANTIBOT_RECAPTCHA_SCORE": "0.7",
|
||||
"USE_AUTH_BASIC": "no",
|
||||
"AUTH_BASIC_LOCATION": "sitewide",
|
||||
"AUTH_BASIC_USER": "changeme",
|
||||
"AUTH_BASIC_PASSWORD": "changeme",
|
||||
"AUTH_BASIC_TEXT": "Restricted area",
|
||||
"USE_BACKUP": "yes",
|
||||
"BACKUP_SCHEDULE": "daily",
|
||||
"BACKUP_ROTATION": "7",
|
||||
"BACKUP_DIRECTORY": "/var/lib/bunkerweb/backups",
|
||||
"USE_BAD_BEHAVIOR": "yes",
|
||||
"BAD_BEHAVIOR_STATUS_CODES": "400 401 403 404 405 429 444",
|
||||
"BAD_BEHAVIOR_THRESHOLD": "10",
|
||||
"BAD_BEHAVIOR_COUNT_TIME": "60",
|
||||
"BAD_BEHAVIOR_BAN_TIME": "86400",
|
||||
"BLACKLIST_RDNS": ".shodan.io .censys.io",
|
||||
"BLACKLIST_RDNS_GLOBAL": "yes",
|
||||
"BLACKLIST_IP_URLS": "https://www.dan.me.uk/torlist/?exit",
|
||||
"BLACKLIST_USER_AGENT_URLS": "https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list",
|
||||
"USE_BROTLI": "no",
|
||||
"BROTLI_TYPES": "application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml",
|
||||
"BROTLI_MIN_LENGTH": "1000",
|
||||
"BROTLI_COMP_LEVEL": "6",
|
||||
"BUNKERNET_SERVER": "https://api.bunkerweb.io",
|
||||
"USE_CORS": "no",
|
||||
"CORS_ALLOW_ORIGIN": "self",
|
||||
"CORS_ALLOW_METHODS": "GET, POST, OPTIONS",
|
||||
"CORS_ALLOW_HEADERS": "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range",
|
||||
"CORS_ALLOW_CREDENTIALS": "no",
|
||||
"CORS_EXPOSE_HEADERS": "Content-Length,Content-Range",
|
||||
"CROSS_ORIGIN_OPENER_POLICY": "same-origin",
|
||||
"CROSS_ORIGIN_EMBEDDER_POLICY": "require-corp",
|
||||
"CROSS_ORIGIN_RESOURCE_POLICY": "same-site",
|
||||
"CORS_MAX_AGE": "86400",
|
||||
"CORS_DENY_REQUEST": "yes",
|
||||
"CLIENT_CACHE_EXTENSIONS": "jpg|jpeg|png|bmp|ico|svg|tif|css|js|otf|ttf|eot|woff|woff2",
|
||||
"CLIENT_CACHE_ETAG": "yes",
|
||||
"CLIENT_CACHE_CONTROL": "public, max-age=15552000",
|
||||
"USE_CUSTOM_SSL": "no",
|
||||
"DATABASE_URI": "sqlite:////var/lib/bunkerweb/db.sqlite3",
|
||||
"DATABASE_LOG_LEVEL": "warning",
|
||||
"USE_DNSBL": "yes",
|
||||
"DNSBL_LIST": "bl.blocklist.de problems.dnsbl.sorbs.net sbl.spamhaus.org xbl.spamhaus.org",
|
||||
"INTERCEPTED_ERROR_CODES": "400 401 403 404 405 413 429 500 501 502 503 504",
|
||||
"USE_GREYLIST": "no",
|
||||
"GREYLIST_RDNS_GLOBAL": "yes",
|
||||
"GZIP_TYPES": "application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml",
|
||||
"GZIP_MIN_LENGTH": "1000",
|
||||
"GZIP_COMP_LEVEL": "5",
|
||||
"GZIP_PROXIED": "no-cache no-store private expired auth",
|
||||
"REMOVE_HEADERS": "Server Expect-CT X-Powered-By X-AspNet-Version X-AspNetMvc-Version Public-Key-Pins",
|
||||
"KEEP_UPSTREAM_HEADERS": "Content-Security-Policy Permissions-Policy X-Frame-Options",
|
||||
"STRICT_TRANSPORT_SECURITY": "max-age=31536000; includeSubDomains; preload",
|
||||
"COOKIE_FLAGS": "* HttpOnly SameSite=Lax",
|
||||
"COOKIE_AUTO_SECURE_FLAG": "yes",
|
||||
"CONTENT_SECURITY_POLICY": "object-src 'none'; form-action 'self'; frame-ancestors 'self';",
|
||||
"CONTENT_SECURITY_POLICY_REPORT_ONLY": "no",
|
||||
"REFERRER_POLICY": "strict-origin-when-cross-origin",
|
||||
"PERMISSIONS_POLICY": "accelerometer=(), ambient-light-sensor=(), attribution-reporting=(), autoplay=(), battery=(), bluetooth=(), browsing-topics=(), camera=(), compute-pressure=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), identity-credentials-get=(), idle-detection=(), local-fonts=(), magnetometer=(), microphone=(), midi=(), otp-credentials=(), payment=(), picture-in-picture=(), publickey-credentials-create=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), speaker-selection=(), storage-access=(), usb=(), web-share=(), window-management=(), xr-spatial-tracking=()",
|
||||
"X_FRAME_OPTIONS": "SAMEORIGIN",
|
||||
"X_CONTENT_TYPE_OPTIONS": "nosniff",
|
||||
"X_XSS_PROTECTION": "1; mode=block",
|
||||
"AUTO_LETS_ENCRYPT": "no",
|
||||
"USE_LETS_ENCRYPT_STAGING": "no",
|
||||
"LETS_ENCRYPT_CLEAR_OLD_CERTS": "no",
|
||||
"USE_LIMIT_REQ": "yes",
|
||||
"LIMIT_REQ_URL": "/",
|
||||
"LIMIT_REQ_RATE": "2r/s",
|
||||
"USE_LIMIT_CONN": "yes",
|
||||
"LIMIT_CONN_MAX_HTTP1": "10",
|
||||
"LIMIT_CONN_MAX_HTTP2": "100",
|
||||
"LIMIT_CONN_MAX_STREAM": "10",
|
||||
"USE_METRICS": "yes",
|
||||
"METRICS_MEMORY_SIZE": "16m",
|
||||
"METRICS_MAX_BLOCKED_REQUESTS": "100",
|
||||
"DISABLE_DEFAULT_SERVER_STRICT_SNI": "no",
|
||||
"REDIRECT_HTTP_TO_HTTPS": "no",
|
||||
"AUTO_REDIRECT_HTTP_TO_HTTPS": "yes",
|
||||
"ALLOWED_METHODS": "GET|POST|HEAD",
|
||||
"MAX_CLIENT_SIZE": "10m",
|
||||
"SSL_PROTOCOLS": "TLSv1.2 TLSv1.3",
|
||||
"HTTP2": "yes",
|
||||
"HTTP3": "no",
|
||||
"HTTP3_ALT_SVC_PORT": "443",
|
||||
"LISTEN_HTTP": "yes",
|
||||
"USE_OPEN_FILE_CACHE": "no",
|
||||
"OPEN_FILE_CACHE": "max=1000 inactive=20s",
|
||||
"OPEN_FILE_CACHE_ERRORS": "yes",
|
||||
"OPEN_FILE_CACHE_MIN_USES": "2",
|
||||
"OPEN_FILE_CACHE_VALID": "30s",
|
||||
"DENY_HTTP_STATUS": "403",
|
||||
"USE_MODSECURITY": "yes",
|
||||
"USE_MODSECURITY_CRS": "yes",
|
||||
"MODSECURITY_CRS_VERSION": "4",
|
||||
"MODSECURITY_SEC_AUDIT_ENGINE": "RelevantOnly",
|
||||
"MODSECURITY_SEC_RULE_ENGINE": "On",
|
||||
"MODSECURITY_SEC_AUDIT_LOG_PARTS": "ABCFHZ",
|
||||
"USE_REAL_IP": "no",
|
||||
"USE_PROXY_PROTOCOL": "no",
|
||||
"REAL_IP_FROM": "192.168.0.0/16 172.16.0.0/12 10.0.0.0/8",
|
||||
"REAL_IP_HEADER": "X-Forwarded-For",
|
||||
"REAL_IP_RECURSIVE": "yes",
|
||||
"REDIRECT_TO_REQUEST_URI": "no",
|
||||
"REDIRECT_TO_STATUS_CODE": "301",
|
||||
"USE_REDIS": "no",
|
||||
"REDIS_PORT": "6379",
|
||||
"REDIS_DATABASE": "0",
|
||||
"REDIS_SSL": "no",
|
||||
"REDIS_SSL_VERIFY": "no",
|
||||
"REDIS_TIMEOUT": "1000",
|
||||
"REDIS_KEEPALIVE_IDLE": "30000",
|
||||
"REDIS_KEEPALIVE_POOL": "10",
|
||||
"USE_REVERSE_PROXY": "no",
|
||||
"REVERSE_PROXY_INTERCEPT_ERRORS": "yes",
|
||||
"REVERSE_PROXY_URL": "/",
|
||||
"REVERSE_PROXY_WS": "no",
|
||||
"REVERSE_PROXY_BUFFERING": "yes",
|
||||
"REVERSE_PROXY_KEEPALIVE": "no",
|
||||
"REVERSE_PROXY_CONNECT_TIMEOUT": "60s",
|
||||
"REVERSE_PROXY_READ_TIMEOUT": "60s",
|
||||
"REVERSE_PROXY_SEND_TIMEOUT": "60s",
|
||||
"USE_PROXY_CACHE": "no",
|
||||
"PROXY_CACHE_PATH_LEVELS": "1:2",
|
||||
"PROXY_CACHE_PATH_ZONE_SIZE": "10m",
|
||||
"PROXY_CACHE_PATH_PARAMS": "max_size=100m",
|
||||
"PROXY_CACHE_METHODS": "GET HEAD",
|
||||
"PROXY_CACHE_MIN_USES": "2",
|
||||
"PROXY_CACHE_KEY": "$scheme$host$request_uri",
|
||||
"PROXY_CACHE_VALID": "200=24h 301=1h 302=24h",
|
||||
"PROXY_NO_CACHE": "$http_pragma $http_authorization",
|
||||
"PROXY_CACHE_BYPASS": "0",
|
||||
"USE_REVERSE_SCAN": "no",
|
||||
"REVERSE_SCAN_PORTS": "22 80 443 3128 8000 8080",
|
||||
"REVERSE_SCAN_TIMEOUT": "500",
|
||||
"GENERATE_SELF_SIGNED_SSL": "no",
|
||||
"SELF_SIGNED_SSL_EXPIRY": "365",
|
||||
"SELF_SIGNED_SSL_SUBJ": "/CN=www.example.com/",
|
||||
"SESSIONS_SECRET": "random",
|
||||
"SESSIONS_NAME": "random",
|
||||
"SESSIONS_IDLING_TIMEOUT": "1800",
|
||||
"SESSIONS_ROLLING_TIMEOUT": "3600",
|
||||
"SESSIONS_ABSOLUTE_TIMEOUT": "86400",
|
||||
"SESSIONS_CHECK_IP": "yes",
|
||||
"SESSIONS_CHECK_USER_AGENT": "yes",
|
||||
"USE_UI": "no",
|
||||
"WHITELIST_IP": "20.191.45.212 40.88.21.235 40.76.173.151 40.76.163.7 20.185.79.47 52.142.26.175 20.185.79.15 52.142.24.149 40.76.162.208 40.76.163.23 40.76.162.191 40.76.162.247",
|
||||
"WHITELIST_RDNS": ".google.com .googlebot.com .yandex.ru .yandex.net .yandex.com .search.msn.com .baidu.com .baidu.jp .crawl.yahoo.net .fwd.linkedin.com .twitter.com .twttr.com .discord.com",
|
||||
"WHITELIST_RDNS_GLOBAL": "yes",
|
||||
"WHITELIST_ASN": "32934"
|
||||
}
|
||||
"default": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import copy
|
||||
import base64
|
||||
from typing import Union
|
||||
|
||||
# Default plugins from docker-compose.ui.yml
|
||||
plugins = [
|
||||
|
|
@ -3313,23 +3314,30 @@ global_config = {
|
|||
}
|
||||
|
||||
|
||||
def get_forms(templates=[], plugins=[], settings={}):
|
||||
def get_forms(templates: list = [], plugins: list = [], settings: dict = {}, render_forms: tuple = ("advanced", "easy", "raw")) -> dict:
|
||||
"""
|
||||
Will generate every needed form using templates, plugins and settings.
|
||||
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).
|
||||
We will format to fit each form type (easy, advanced, raw) in case
|
||||
"""
|
||||
forms = {"advanced": {}, "easy": {}, "raw": {}}
|
||||
forms = {}
|
||||
for form in render_forms:
|
||||
forms[form] = {}
|
||||
|
||||
for template in templates:
|
||||
forms["advanced"][template.get("name")] = set_advanced(template, plugins, settings)
|
||||
forms["raw"][template.get("name")] = set_raw(template, plugins, settings)
|
||||
forms["easy"][template.get("name")] = set_easy(template, plugins, settings)
|
||||
if "advanced" in forms:
|
||||
forms["advanced"][template.get("name")] = set_advanced(template, plugins, settings)
|
||||
|
||||
if "raw" in forms:
|
||||
forms["raw"][template.get("name")] = set_raw(template, plugins, settings)
|
||||
|
||||
if "easy" in forms:
|
||||
forms["easy"][template.get("name")] = set_easy(template, plugins, settings)
|
||||
|
||||
return forms
|
||||
|
||||
|
||||
def set_easy(template, plugins_base, settings):
|
||||
def set_easy(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Prepare the easy form based on the template and plugins data.
|
||||
We need to loop on each steps and prepare settings and configs for each step.
|
||||
|
|
@ -3375,7 +3383,7 @@ def set_easy(template, plugins_base, settings):
|
|||
return steps
|
||||
|
||||
|
||||
def set_raw(template, plugins_base, settings):
|
||||
def set_raw(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Set the raw form based on the template and plugins data.
|
||||
It consists of keeping only the value or default value for each plugin settings.
|
||||
|
|
@ -3400,7 +3408,14 @@ def set_raw(template, plugins_base, settings):
|
|||
|
||||
# Then override by service settings
|
||||
if setting in settings:
|
||||
raw_value = settings[setting].get("value", value.get("value", value.get("default")))
|
||||
val = settings[setting].get("value", value.get("value"))
|
||||
|
||||
|
||||
# Check if value is same as default
|
||||
# If case, we don't need to add it
|
||||
default_val = value.get("default")
|
||||
if val == default_val:
|
||||
raw_value = None
|
||||
|
||||
# Add value only if exists
|
||||
if raw_value:
|
||||
|
|
@ -3409,7 +3424,7 @@ def set_raw(template, plugins_base, settings):
|
|||
return raw_settings
|
||||
|
||||
|
||||
def set_advanced(template, plugins_base, settings):
|
||||
def set_advanced(template: list, plugins_base: list, settings: dict) -> dict:
|
||||
"""
|
||||
Set the advanced form based on the template and plugins data.
|
||||
It consists of formatting each plugin settings to be used in the advanced form.
|
||||
|
|
@ -3554,7 +3569,7 @@ def get_multiple_from_settings(settings, multiples):
|
|||
return multiple_settings
|
||||
|
||||
|
||||
def set_multiples(template, format_plugins, service_settings):
|
||||
def set_multiples(template, format_plugins, settings):
|
||||
"""
|
||||
Set the multiples settings for each plugin.
|
||||
"""
|
||||
|
|
@ -3593,7 +3608,7 @@ def set_multiples(template, format_plugins, service_settings):
|
|||
# Get all settings from template that are multiples
|
||||
template_multiples = get_multiple_from_template(template, multiples)
|
||||
# Get all settings from service settings / global config that are multiples
|
||||
service_multiples = get_multiple_from_settings(service_settings, multiples)
|
||||
service_multiples = get_multiple_from_settings(settings, multiples)
|
||||
# Get service multiples if at least one, else use template multiples
|
||||
plugin["multiples"] = service_multiples if len(service_multiples) else template_multiples
|
||||
|
||||
|
|
@ -3601,13 +3616,13 @@ def set_multiples(template, format_plugins, service_settings):
|
|||
|
||||
|
||||
def format_setting(
|
||||
setting_name,
|
||||
setting_value,
|
||||
total_settings,
|
||||
loop_id,
|
||||
template_settings,
|
||||
service_settings,
|
||||
):
|
||||
setting_name: str,
|
||||
setting_value: Union[str, int],
|
||||
total_settings: Union[str, int],
|
||||
loop_id: Union[str, int],
|
||||
template_settings: dict,
|
||||
settings: dict,
|
||||
) -> dict:
|
||||
"""
|
||||
Format a setting in order to be used with form builder.
|
||||
This will only set value for none multiple settings.
|
||||
|
|
@ -3652,18 +3667,18 @@ def format_setting(
|
|||
|
||||
# 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 service_settings and not "multiple" in setting_value:
|
||||
setting_value["value"] = service_settings[setting_name].get("value", setting_value.get("value", setting_value.get("default")))
|
||||
setting_value["method"] = service_settings[setting_name].get("method", "ui")
|
||||
if setting_name in settings and not "multiple" in setting_value:
|
||||
setting_value["value"] = settings[setting_name].get("value", setting_value.get("value", setting_value.get("default")))
|
||||
setting_value["method"] = settings[setting_name].get("method", "ui")
|
||||
|
||||
# Then override by service settings
|
||||
if setting_name in service_settings:
|
||||
setting_value["disabled"] = False if service_settings[setting_name].get("method", "ui") in ("ui", "default", "manual") else True
|
||||
if setting_name in settings:
|
||||
setting_value["disabled"] = False if settings[setting_name].get("method", "ui") in ("ui", "default", "manual") else True
|
||||
|
||||
# Prepare popover checking "help", "context"
|
||||
popovers = []
|
||||
|
||||
if (setting_value.get("disabled", False)) and service_settings[setting_name].get("method", "ui") not in ("ui", "default", "manual"):
|
||||
if (setting_value.get("disabled", False)) and settings[setting_name].get("method", "ui") not in ("ui", "default", "manual"):
|
||||
popovers.append(
|
||||
{
|
||||
"iconName": "trespass",
|
||||
|
|
@ -3691,7 +3706,7 @@ def format_setting(
|
|||
return setting_value
|
||||
|
||||
|
||||
def global_config_builder(plugins, settings):
|
||||
def global_config_builder(plugins: list, settings: dict) -> str:
|
||||
"""Render forms with global config data.
|
||||
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
|
||||
"""
|
||||
|
|
@ -3721,19 +3736,17 @@ def global_config_builder(plugins, settings):
|
|||
{
|
||||
"type": "Templates",
|
||||
"data": {
|
||||
"templates": get_forms(templates, plugins, settings),
|
||||
"templates": get_forms(templates, plugins, settings, ("advanced", "raw")),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
return builder
|
||||
# return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
|
||||
|
||||
|
||||
output = global_config_builder(plugins, global_config)
|
||||
print(output)
|
||||
with open("globalconfig.json", "w") as f:
|
||||
json.dump(output, f, indent=4)
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -41,6 +41,10 @@ export default defineConfig({
|
|||
input: {
|
||||
home: resolve(__dirname, "./dashboard/pages/home/index.html"),
|
||||
instances: resolve(__dirname, "./dashboard/pages/instances/index.html"),
|
||||
global_config: resolve(
|
||||
__dirname,
|
||||
"./dashboard/pages/global-config/index.html"
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1161,7 +1161,7 @@ def services():
|
|||
)
|
||||
|
||||
|
||||
@app.route("/global_config", methods=["GET", "POST"])
|
||||
@app.route("/global-config", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def global_config():
|
||||
if request.method == "POST":
|
||||
|
|
@ -1232,13 +1232,10 @@ def global_config():
|
|||
)
|
||||
)
|
||||
|
||||
# Display global config
|
||||
global_config = app.config["DB"].get_config(global_only=True, methods=True)
|
||||
# Display global config
|
||||
plugins = app.config["CONFIG"].get_plugins()
|
||||
print(global_config, flush=True)
|
||||
data_server_builder = global_config_builder(plugins, global_config)
|
||||
return render_template("global_config.html", data_server_builder=global_config, dumped_global_config=dumps(global_config))
|
||||
return render_template("global-config.html", data_server_builder=data_server_builder)
|
||||
|
||||
|
||||
@app.route("/configs", methods=["GET", "POST"])
|
||||
|
|
|
|||
30
src/ui/templates/global-config.html
vendored
Normal file
30
src/ui/templates/global-config.html
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico" />
|
||||
<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 | Global config</title>
|
||||
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/global_config-CkvHODXe.js"></script>
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Title-B1qYFCEw.js">
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-CEsjkeUs.js">
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/form-BpBCT1YO.js">
|
||||
<link rel="stylesheet" crossorigin href="assets/global_config-D2kv0NCW.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% set data_server_flash = [] %}
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
{% if data_server_flash.append({"type": "error" if category == "error" else "success", "title": "dashboard_error" if category == "error" else "dashboard_success", "message": message}) %}{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<div class='hidden' data-csrf-token='{{ csrf_token() }}'></div>
|
||||
<div class='hidden' data-server-global='{{data_server_global if data_server_global else {}}}'></div>
|
||||
<div class='hidden' data-server-flash='{{data_server_flash|tojson}}'></div>
|
||||
<div class='hidden' data-server-builder='{{data_server_builder}}'></div>
|
||||
<div id='app'></div>
|
||||
</body>
|
||||
</html>
|
||||
74
src/ui/templates/global_config.html
vendored
74
src/ui/templates/global_config.html
vendored
|
|
@ -1,74 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
{% set attribute_name = "global-config" %}
|
||||
<div data-global-config-tabs-select-container
|
||||
class="z-100 w-full grid grid-cols-12 h-fit max-h-100 sm:max-h-125 col-span-12 md:col-span-6 lg:col-span-4 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<div data-{{ current_endpoint }}-tabs-select-header class="col-span-12">
|
||||
<div class="flex flex-col xs:flex-row xs:justify-start xs:items-center gap-x-4 gap-y-2 mb-4">
|
||||
<h5 class="transition duration-300 ease-in-out 0 ml-2 font-bold text-md uppercase dark:text-white/90 mb-0">PLUGINS</h5>
|
||||
</div>
|
||||
{% include "settings_tabs_select.html" %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- filter -->
|
||||
{% set filters = [
|
||||
{
|
||||
"type": "input",
|
||||
"name": "Search",
|
||||
"label": "search",
|
||||
"id": "keyword",
|
||||
"placeholder": "keyword",
|
||||
"pattern": "(.*?)"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "Context",
|
||||
"id": "context",
|
||||
"value": "all",
|
||||
"values": [
|
||||
"all",
|
||||
"global",
|
||||
"multisite"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "Type",
|
||||
"id": "type",
|
||||
"value": "all",
|
||||
"values": [
|
||||
"all",
|
||||
"core",
|
||||
"external",
|
||||
"pro"
|
||||
]
|
||||
}
|
||||
] %}
|
||||
{% include "card_filter.html" %}
|
||||
<!-- end filter -->
|
||||
<div data-global-config-plugins-container
|
||||
class="col-span-12 gap-y-4 grid grid-cols-12">
|
||||
<div data-global-config-settings
|
||||
class="hidden"
|
||||
data-value="{{ dumped_global_config }}"></div>
|
||||
<!-- form global conf -->
|
||||
<form data-global-config-form
|
||||
id="form-edit-global-config"
|
||||
method="post"
|
||||
class="flex flex-col justify-between overflow-hidden overflow-y-auto col-span-12 break-words bg-white shadow-xl p-4 dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<!-- plugin item -->
|
||||
{% include "settings_plugins.html" %}
|
||||
<!-- end plugin item -->
|
||||
<!-- submit -->
|
||||
<div class="flex w-full justify-center mt-8 mb-2">
|
||||
<button {% if is_readonly %}disabled{% endif %}
|
||||
type="submit"
|
||||
class="valid-btn">SAVE</button>
|
||||
</div>
|
||||
<!-- end submit -->
|
||||
</form>
|
||||
<!--end form global conf -->
|
||||
{% include "filter_nomatch.html" %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
7
src/ui/templates/home.html
vendored
7
src/ui/templates/home.html
vendored
|
|
@ -6,9 +6,10 @@
|
|||
<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 | DASHBOARD</title>
|
||||
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/home-BnrNYFnz.js"></script>
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Title-B_4IDnhH.js">
|
||||
<title>BunkerWeb | Home</title>
|
||||
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/home-DH_UDl3D.js"></script>
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Title-B1qYFCEw.js">
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Text-CEsjkeUs.js">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
|||
7
src/ui/templates/instances.html
vendored
7
src/ui/templates/instances.html
vendored
|
|
@ -6,9 +6,10 @@
|
|||
<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 | DASHBOARD</title>
|
||||
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/instances-DfV5PghU.js"></script>
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Title-B_4IDnhH.js">
|
||||
<title>BunkerWeb | Instances</title>
|
||||
<script type="module" crossorigin nonce="{{ script_nonce }}" src="assets/instances-LtBmJEvG.js"></script>
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/Title-B1qYFCEw.js">
|
||||
<link rel="modulepreload" crossorigin nonce="{{ script_nonce }}" href="assets/form-BpBCT1YO.js">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
|||
Loading…
Reference in a new issue