update builder + add logs page

* move base64 encode logic from builder files to main.py in order to get same logic on client/tests/builder and src/builder
* add logs.vue page + update builder and vite config to render it
* add logs page i18n
*logs base builder done : render when no log files, when no log selected, when a log without value is selected or when a log with value is selected
* update logs main.py route to work with builder
This commit is contained in:
Jordan Blasenhauer 2024-08-07 11:35:10 +02:00
parent 3605242548
commit 081d953bdb
28 changed files with 380 additions and 119 deletions

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms, get_service_settings
@ -39,4 +36,4 @@ def advanced_mode_builder(templates: list[dict], plugins: list, global_config: d
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms, get_service_settings
@ -39,4 +36,4 @@ def easy_mode_builder(templates: list[dict], plugins: list, global_config: dict,
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,5 +1,3 @@
import base64
import json
from os.path import join, sep
from sys import path as sys_path
@ -38,4 +36,4 @@ def global_config_builder(templates: list[dict], plugins: list, settings: dict)
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from os.path import join, sep
from sys import path as sys_path
@ -91,4 +88,4 @@ def home_builder(data: dict) -> str:
builder = [version_card, version_num_card, instances_card, services_card, plugins_card]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from os.path import join, sep
from sys import path as sys_path
from typing import List
@ -57,4 +54,4 @@ def instances_builder(instances: List[Instance]) -> str:
builder.append(instance)
return base64.b64encode(json.dumps(builder).encode("utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from os.path import join, sep
from sys import path as sys_path
@ -141,7 +138,7 @@ def jobs_builder(jobs):
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder
def get_jobs_list(jobs):

89
src/ui/builder/logs.py Normal file
View file

@ -0,0 +1,89 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.widgets import title_widget
def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str = "") -> str:
if not files:
builder = [
{
"type": "void",
"widgets": [{"type": "MessageUnmatch", "data": {"text": "logs_no_files_found"}}],
}
]
return builder
file_select = {
"type": "Fields",
"data": {
"setting": {
"id": "logs-select-file",
"label": "logs_select_file",
"inpType": "select",
"name": "logs-select-file",
"onlyDown": True,
"value": current_file,
"values": files,
"columns": {
"pc": 4,
"tablet": 6,
"mobile": 12,
},
"maxBtnChars": 20,
"attrs": {
"data-log": "true",
},
"popovers": [
{
"iconName": "info",
"text": "logs_select_file_info",
},
],
}
},
}
if not raw_data:
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, {"type": "MessageUnmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
}
]
return builder
editor = {
"type": "Fields",
"data": {
"setting": {
"containerClass": "mt-4",
"id": "logs-file-content",
"label": "logs_file_content",
"inpType": "editor",
"name": "logs-file-content",
"value": raw_data,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
}
},
}
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, editor],
}
]
return builder

View file

@ -1,5 +1,3 @@
import base64
import json
from os.path import join, sep
from sys import path as sys_path
@ -47,4 +45,4 @@ def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict,
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,8 +1,5 @@
import base64
import json
from typing import Union
from os.path import join, sep
from sys import path as sys_path
@ -122,7 +119,7 @@ def services_builder(services):
},
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder
def services_settings(settings: dict) -> dict:

View file

@ -110,7 +110,8 @@ 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 "modes" in file.parts:
is_parts = any(part in file.parts for part in ("global-config", "jobs", "services", "modes", "logs", "instances"))
if is_parts:
file_html = base_html.replace("data_server_builder[1:-1]", "data_server_builder")
content = file.read_text()

View file

@ -0,0 +1,53 @@
<script setup>
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
import Title from "@components/Widget/Title.vue";
import Fields from "@components/Form/Fields.vue";
import MessageUnmatch from "@components/Message/Unmatch.vue";
import { useEqualStr } from "@utils/global.js";
/**
** @name Builder/Logs.vue
* @description This component is lightweight builder containing only the necessary components to create the logs page.
* @param {array} builder - Array of containers and widgets
*/
const props = defineProps({
builder: {
type: Array,
required: true,
},
});
</script>
<template>
<!-- top level grid (layout) -->
<GridLayout
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
>
<!-- widget grid -->
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<MessageUnmatch
v-if="useEqualStr(widget.type, 'MessageUnmatch')"
v-bind="widget.data"
/>
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
<Fields
v-if="useEqualStr(widget.type, 'Fields')"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>
</template>

View file

@ -194,6 +194,8 @@
"instances_status": "status",
"instances_active": "active",
"instances_inactive": "inactive",
"instances_creation_date": "creation date",
"instances_last_seen": "last seen",
"global_config_title": "Global configuration",
"global_config_subtitle": "Manage your global settings.",
"jobs_title": "Jobs list",
@ -297,5 +299,12 @@
"services_settings_table_status": "Status",
"services_mode_title": "Service mode",
"services_mode_subtitle": "Manage your service settings.",
"services_manage_subtitle": "Manage your service settings."
"services_manage_subtitle": "Manage your service settings.",
"logs_title": "Logs",
"logs_not_found": "No logs found",
"logs_no_files_found": "No log files found",
"logs_select_file": "Select a log file",
"logs_select_file_info": "Log files are retrieve using syslog under the hood.",
"logs_not_selected_or_not_found": "No log file selected or content not found",
"logs_file_content": "Log content"
}

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms, get_service_settings
@ -39,4 +36,4 @@ def advanced_mode_builder(templates: list[dict], plugins: list, global_config: d
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms, get_service_settings
@ -39,4 +36,4 @@ def easy_mode_builder(templates: list[dict], plugins: list, global_config: dict,
],
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.widgets import stat_widget
@ -84,4 +81,4 @@ def home_builder(data: dict) -> str:
builder = [version_card, version_num_card, instances_card, services_card, plugins_card]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.widgets import instance_widget
@ -47,4 +44,4 @@ def instances_builder(instances: list) -> str:
builder.append(instance)
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.widgets import title_widget, table_widget
@ -134,7 +131,7 @@ def jobs_builder(jobs):
}
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder
def get_jobs_list(jobs):

View file

@ -0,0 +1,82 @@
from .utils.widgets import title_widget
def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str = "") -> str:
if not files:
builder = [
{
"type": "void",
"widgets": [{"type": "MessageUnmatch", "data": {"text": "logs_no_files_found"}}],
}
]
return builder
file_select = {
"type": "Fields",
"data": {
"setting": {
"id": "logs-select-file",
"label": "logs_select_file",
"inpType": "select",
"name": "logs-select-file",
"onlyDown": True,
"value": current_file,
"values": files,
"columns": {
"pc": 4,
"tablet": 6,
"mobile": 12,
},
"maxBtnChars": 20,
"attrs": {
"data-log": "true",
},
"popovers": [
{
"iconName": "info",
"text": "logs_select_file_info",
},
],
}
},
}
if not raw_data:
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, {"type": "MessageUnmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
}
]
return builder
editor = {
"type": "Fields",
"data": {
"setting": {
"containerClass": "mt-4",
"id": "logs-file-content",
"label": "logs_file_content",
"inpType": "editor",
"name": "logs-file-content",
"value": raw_data,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
}
},
}
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, editor],
}
]
return builder

View file

@ -1,6 +1,3 @@
import base64
import json
from .utils.form import get_forms, get_service_settings

View file

@ -1,5 +1,3 @@
import base64
import json
from typing import Union
from .utils.widgets import title_widget, table_widget
@ -114,7 +112,7 @@ def services_builder(services):
},
]
return base64.b64encode(bytes(json.dumps(builder), "utf-8")).decode("ascii")
return builder
def services_settings(settings: dict) -> dict:

View file

@ -0,0 +1,68 @@
[
{
"type": "card",
"containerColumns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"widgets": [
{
"type": "Title",
"data": {
"title": "logs_title"
}
},
{
"type": "Fields",
"data": {
"setting": {
"id": "logs-select-file",
"label": "logs_select_file",
"inpType": "select",
"name": "logs-select-file",
"onlyDown": true,
"value": "",
"values": [
"file1",
"file2"
],
"columns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"maxBtnChars": 20,
"attrs": {
"data-log": "true"
},
"popovers": [
{
"iconName": "info",
"text": "logs_select_file_info"
}
]
}
}
},
{
"type": "Fields",
"data": {
"setting": {
"containerClass": "mt-4",
"id": "logs-file-content",
"label": "logs_file_content",
"inpType": "editor",
"name": "logs-file-content",
"value": "gefesfesfsefes",
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
}
}
}
}
]
}
]

View file

@ -0,0 +1,17 @@
import json
import base64
from builder.logs import logs_builder
files = ["file1", "file2"]
current_file = ""
raw_data = "gefesfesfsefes"
output = logs_builder(files, current_file, raw_data)
with open("logs.json", "w") as f:
json.dump(output, f, indent=4)
output_base64_bytes = base64.b64encode(bytes(json.dumps(output), "utf-8"))
output_base64_string = output_base64_bytes.decode("ascii")
with open("logs.txt", "w") as f:
f.write(output_base64_string)

View file

@ -0,0 +1 @@
W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogMTIsICJ0YWJsZXQiOiAxMiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRpdGxlIiwgImRhdGEiOiB7InRpdGxlIjogImxvZ3NfdGl0bGUifX0sIHsidHlwZSI6ICJGaWVsZHMiLCAiZGF0YSI6IHsic2V0dGluZyI6IHsiaWQiOiAibG9ncy1zZWxlY3QtZmlsZSIsICJsYWJlbCI6ICJsb2dzX3NlbGVjdF9maWxlIiwgImlucFR5cGUiOiAic2VsZWN0IiwgIm5hbWUiOiAibG9ncy1zZWxlY3QtZmlsZSIsICJvbmx5RG93biI6IHRydWUsICJ2YWx1ZSI6ICIiLCAidmFsdWVzIjogWyJmaWxlMSIsICJmaWxlMiJdLCAiY29sdW1ucyI6IHsicGMiOiA0LCAidGFibGV0IjogNiwgIm1vYmlsZSI6IDEyfSwgIm1heEJ0bkNoYXJzIjogMjAsICJhdHRycyI6IHsiZGF0YS1sb2ciOiAidHJ1ZSJ9LCAicG9wb3ZlcnMiOiBbeyJpY29uTmFtZSI6ICJpbmZvIiwgInRleHQiOiAibG9nc19zZWxlY3RfZmlsZV9pbmZvIn1dfX19LCB7InR5cGUiOiAiRmllbGRzIiwgImRhdGEiOiB7InNldHRpbmciOiB7ImNvbnRhaW5lckNsYXNzIjogIm10LTQiLCAiaWQiOiAibG9ncy1maWxlLWNvbnRlbnQiLCAibGFiZWwiOiAibG9nc19maWxlX2NvbnRlbnQiLCAiaW5wVHlwZSI6ICJlZGl0b3IiLCAibmFtZSI6ICJsb2dzLWZpbGUtY29udGVudCIsICJ2YWx1ZSI6ICJnZWZlc2Zlc2ZzZWZlcyIsICJjb2x1bW5zIjogeyJwYyI6IDEyLCAidGFibGV0IjogMTIsICJtb2JpbGUiOiAxMn19fX1dfV0=

View file

@ -1,63 +1,11 @@
[
{
"type": "card",
"containerColumns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"type": "void",
"widgets": [
{
"type": "Title",
"type": "MessageUnmatch",
"data": {
"title": "app1.example.com",
"type": "container",
"lowercase": true
}
},
{
"type": "Subtitle",
"data": {
"subtitle": "services_manage_subtitle",
"type": "container",
"subtitleClass": "mb-4"
}
},
{
"type": "Templates",
"data": {
"templates": {
"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",
"USE_BLACKLIST": "no",
"USE_BUNKERNET": "no",
"CORS_ALLOW_ORIGIN": "self",
"CROSS_ORIGIN_OPENER_POLICY": "same-origin",
"CROSS_ORIGIN_EMBEDDER_POLICY": "require-corp",
"CROSS_ORIGIN_RESOURCE_POLICY": "same-site",
"USE_CLIENT_CACHE": "yes",
"USE_GZIP": "yes",
"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",
"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=()",
"DISABLE_DEFAULT_SERVER": "yes",
"SERVE_FILES": "no",
"SEND_ANONYMOUS_REPORT": "no",
"MODSECURITY_CRS_VERSION": "4",
"USE_REVERSE_PROXY": "yes",
"REVERSE_PROXY_HOST": "http://app1:8080",
"USE_WHITELIST": "no"
}
}
},
"operation": "edit",
"old_service_name": ""
"text": "logs_not_found"
}
}
]

View file

@ -1 +1 @@
W3sidHlwZSI6ICJjYXJkIiwgImNvbnRhaW5lckNvbHVtbnMiOiB7InBjIjogMTIsICJ0YWJsZXQiOiAxMiwgIm1vYmlsZSI6IDEyfSwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRpdGxlIiwgImRhdGEiOiB7InRpdGxlIjogImFwcDEuZXhhbXBsZS5jb20iLCAidHlwZSI6ICJjb250YWluZXIiLCAibG93ZXJjYXNlIjogdHJ1ZX19LCB7InR5cGUiOiAiU3VidGl0bGUiLCAiZGF0YSI6IHsic3VidGl0bGUiOiAic2VydmljZXNfbWFuYWdlX3N1YnRpdGxlIiwgInR5cGUiOiAiY29udGFpbmVyIiwgInN1YnRpdGxlQ2xhc3MiOiAibWItNCJ9fSwgeyJ0eXBlIjogIlRlbXBsYXRlcyIsICJkYXRhIjogeyJ0ZW1wbGF0ZXMiOiB7InJhdyI6IHsiZGVmYXVsdCI6IHsiTVVMVElTSVRFIjogInllcyIsICJTRVJWRVJfTkFNRSI6ICJhcHAxLmV4YW1wbGUuY29tIiwgIkxPR19MRVZFTCI6ICJpbmZvIiwgIkFQSV9XSElURUxJU1RfSVAiOiAiMTI3LjAuMC4wLzI0IDEwLjIwLjMwLjAvMjQiLCAiQlVOS0VSV0VCX0lOU1RBTkNFUyI6ICJidW5rZXJ3ZWIiLCAiVVNFX0JMQUNLTElTVCI6ICJubyIsICJVU0VfQlVOS0VSTkVUIjogIm5vIiwgIkNPUlNfQUxMT1dfT1JJR0lOIjogInNlbGYiLCAiQ1JPU1NfT1JJR0lOX09QRU5FUl9QT0xJQ1kiOiAic2FtZS1vcmlnaW4iLCAiQ1JPU1NfT1JJR0lOX0VNQkVEREVSX1BPTElDWSI6ICJyZXF1aXJlLWNvcnAiLCAiQ1JPU1NfT1JJR0lOX1JFU09VUkNFX1BPTElDWSI6ICJzYW1lLXNpdGUiLCAiVVNFX0NMSUVOVF9DQUNIRSI6ICJ5ZXMiLCAiVVNFX0daSVAiOiAieWVzIiwgIlJFTU9WRV9IRUFERVJTIjogIlNlcnZlciBFeHBlY3QtQ1QgWC1Qb3dlcmVkLUJ5IFgtQXNwTmV0LVZlcnNpb24gWC1Bc3BOZXRNdmMtVmVyc2lvbiBQdWJsaWMtS2V5LVBpbnMiLCAiS0VFUF9VUFNUUkVBTV9IRUFERVJTIjogIkNvbnRlbnQtU2VjdXJpdHktUG9saWN5IFBlcm1pc3Npb25zLVBvbGljeSBYLUZyYW1lLU9wdGlvbnMiLCAiU1RSSUNUX1RSQU5TUE9SVF9TRUNVUklUWSI6ICJtYXgtYWdlPTMxNTM2MDAwOyBpbmNsdWRlU3ViRG9tYWluczsgcHJlbG9hZCIsICJQRVJNSVNTSU9OU19QT0xJQ1kiOiAiYWNjZWxlcm9tZXRlcj0oKSwgYW1iaWVudC1saWdodC1zZW5zb3I9KCksIGF0dHJpYnV0aW9uLXJlcG9ydGluZz0oKSwgYXV0b3BsYXk9KCksIGJhdHRlcnk9KCksIGJsdWV0b290aD0oKSwgYnJvd3NpbmctdG9waWNzPSgpLCBjYW1lcmE9KCksIGNvbXB1dGUtcHJlc3N1cmU9KCksIGRpc3BsYXktY2FwdHVyZT0oKSwgZG9jdW1lbnQtZG9tYWluPSgpLCBlbmNyeXB0ZWQtbWVkaWE9KCksIGV4ZWN1dGlvbi13aGlsZS1ub3QtcmVuZGVyZWQ9KCksIGV4ZWN1dGlvbi13aGlsZS1vdXQtb2Ytdmlld3BvcnQ9KCksIGZ1bGxzY3JlZW49KCksIGdhbWVwYWQ9KCksIGdlb2xvY2F0aW9uPSgpLCBneXJvc2NvcGU9KCksIGhpZD0oKSwgaWRlbnRpdHktY3JlZGVudGlhbHMtZ2V0PSgpLCBpZGxlLWRldGVjdGlvbj0oKSwgbG9jYWwtZm9udHM9KCksIG1hZ25ldG9tZXRlcj0oKSwgbWljcm9waG9uZT0oKSwgbWlkaT0oKSwgb3RwLWNyZWRlbnRpYWxzPSgpLCBwYXltZW50PSgpLCBwaWN0dXJlLWluLXBpY3R1cmU9KCksIHB1YmxpY2tleS1jcmVkZW50aWFscy1jcmVhdGU9KCksIHB1YmxpY2tleS1jcmVkZW50aWFscy1nZXQ9KCksIHNjcmVlbi13YWtlLWxvY2s9KCksIHNlcmlhbD0oKSwgc3BlYWtlci1zZWxlY3Rpb249KCksIHN0b3JhZ2UtYWNjZXNzPSgpLCB1c2I9KCksIHdlYi1zaGFyZT0oKSwgd2luZG93LW1hbmFnZW1lbnQ9KCksIHhyLXNwYXRpYWwtdHJhY2tpbmc9KCkiLCAiRElTQUJMRV9ERUZBVUxUX1NFUlZFUiI6ICJ5ZXMiLCAiU0VSVkVfRklMRVMiOiAibm8iLCAiU0VORF9BTk9OWU1PVVNfUkVQT1JUIjogIm5vIiwgIk1PRFNFQ1VSSVRZX0NSU19WRVJTSU9OIjogIjQiLCAiVVNFX1JFVkVSU0VfUFJPWFkiOiAieWVzIiwgIlJFVkVSU0VfUFJPWFlfSE9TVCI6ICJodHRwOi8vYXBwMTo4MDgwIiwgIlVTRV9XSElURUxJU1QiOiAibm8ifX19LCAib3BlcmF0aW9uIjogImVkaXQiLCAib2xkX3NlcnZpY2VfbmFtZSI6ICIifX1dfV0=
W3sidHlwZSI6ICJ2b2lkIiwgIndpZGdldHMiOiBbeyJ0eXBlIjogIk1lc3NhZ2VVbm1hdGNoIiwgImRhdGEiOiB7InRleHQiOiAibG9nc19ub3RfZm91bmQifX1dfV0=

View file

@ -52,6 +52,7 @@ export default defineConfig({
jobs: resolve(__dirname, "./dashboard/pages/jobs/index.html"),
services: resolve(__dirname, "./dashboard/pages/services/index.html"),
modes: resolve(__dirname, "./dashboard/pages/modes/index.html"),
logs: resolve(__dirname, "./dashboard/pages/logs/index.html"),
},
},
},

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python3
import json
import base64
from contextlib import suppress
from math import floor
from multiprocessing import Manager
@ -60,6 +61,7 @@ from builder.services import services_builder
from builder.raw_mode import raw_mode_builder
from builder.advanced_mode import advanced_mode_builder
from builder.easy_mode import easy_mode_builder
from builder.logs import logs_builder
from common_utils import get_version # type: ignore
from logger import setup_logger # type: ignore
@ -937,6 +939,7 @@ def home():
}
data_server_builder = home_builder(data)
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("home.html", data_server_builder=json.dumps(data_server_builder))
@ -1141,7 +1144,9 @@ def instances():
instances = app.bw_instances_utils.get_instances()
data_server_builder = instances_builder(instances)
return render_template("instances.html", title="Instances", data_server_builder=json.dumps(data_server_builder))
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("instances.html", title="Instances", data_server_builder=data_server_builder)
def get_service_data(page_name: str):
@ -1356,6 +1361,8 @@ def services_modes():
TEMPLATE_PLACEHOLDER, plugins, global_config, total_config, service_name or "new", False if service_name else True
)
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("modes.html", data_server_builder=data_server_builder)
@ -1406,6 +1413,7 @@ def services():
services.sort(key=lambda x: x["SERVER_NAME"]["value"])
data_server_builder = services_builder(services)
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("services.html", data_server_builder=data_server_builder)
@ -1479,6 +1487,8 @@ def global_config():
global_config = app.bw_config.get_config(global_only=True, methods=True)
plugins = app.bw_config.get_plugins()
data_server_builder = global_config_builder(TEMPLATE_PLACEHOLDER, plugins, global_config)
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("global-config.html", data_server_builder=data_server_builder)
@ -2124,7 +2134,33 @@ def cache():
@app.route("/logs", methods=["GET"])
@login_required
def logs():
return render_template("logs.html", instances=app.bw_instances_utils.get_instances(), username=current_user.get_id())
# Case not Linux, return empty ATM
if not sbin_nginx_path.is_file():
data_server_builder = logs_builder()
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("logs.html", data_server_builder=data_server_builder)
# Else get all the files in a list of string
files = []
for file in Path(sep, "var", "log", "bunkerweb").iterdir():
if file.is_file():
files.append(file.name)
current_file = request.args.get("file", "")
# Check if a file is in files list
if current_file not in files:
current_file = ""
# Case there is a file, get the file content
raw_data = ""
if current_file:
with open(Path(sep, "var", "log", "bunkerweb", current_file), encoding="utf-8") as f:
raw_data = f.read()
data_server_builder = logs_builder(files, current_file, raw_data)
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("logs.html", data_server_builder=data_server_builder)
@app.route("/logs/local", methods=["GET"])
@ -2605,6 +2641,7 @@ def bans():
@login_required
def jobs():
data_server_builder = jobs_builder(DB.get_jobs())
data_server_builder = base64.b64encode(bytes(json.dumps(data_server_builder), "utf-8")).decode("ascii")
return render_template("jobs.html", data_server_builder=data_server_builder)