mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
started bans page and format
This commit is contained in:
parent
6d14ad67c6
commit
9881fe11c6
7 changed files with 381 additions and 2 deletions
60
vuejs/client/src/components/Builder/Bans.vue
Normal file
60
vuejs/client/src/components/Builder/Bans.vue
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<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 Subtitle from "@components/Widget/Subtitle.vue";
|
||||
import Table from "@components/Widget/Table.vue";
|
||||
import ListPairs from "@components/List/Pairs.vue";
|
||||
import MessageUnmatch from "@components/Message/Unmatch.vue";
|
||||
|
||||
/**
|
||||
@name Builder/Bans.vue
|
||||
@description This component is lightweight builder containing only the necessary components to create the bans page.
|
||||
@example
|
||||
[
|
||||
{
|
||||
type: "card",
|
||||
gridLayoutClass: "transparent",
|
||||
widgets: [{ type: "MessageUnmatch", data: { text: "bans_not_found" } }],
|
||||
},
|
||||
];
|
||||
@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="widget.type === 'MessageUnmatch'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title v-if="widget.type === 'Title'" v-bind="widget.data" />
|
||||
<Subtitle v-if="widget.type === 'Subtitle'" v-bind="widget.data" />
|
||||
<Table v-if="widget.type === 'Table'" v-bind="widget.data" />
|
||||
<ListPairs v-if="widget.type === 'ListPairs'" v-bind="widget.data" />
|
||||
</template>
|
||||
</Grid>
|
||||
</GridLayout>
|
||||
</template>
|
||||
|
|
@ -242,5 +242,11 @@
|
|||
"reports_table_data": "Data",
|
||||
"reports_total": "Total reports",
|
||||
"reports_top_status": "Top status code",
|
||||
"reports_top_reason": "Top reason"
|
||||
"reports_top_reason": "Top reason",
|
||||
"bans_search" : "Search bans",
|
||||
"bans_search_desc" : "Search within ban ip, ban start / end date",
|
||||
"bans_reason": "Reason",
|
||||
"bans_reason_desc": "Reason is the method that triggered the ban.",
|
||||
"bans_terms": "Interval",
|
||||
"bans_terms_desc": "Order of magnitude before unban."
|
||||
}
|
||||
|
|
|
|||
41
vuejs/client/src/pages/bans/Bans.vue
Normal file
41
vuejs/client/src/pages/bans/Bans.vue
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderBans from "@components/Builder/Bans.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/Bans.vue
|
||||
@description This component is the ban page.
|
||||
This page displays global information about bans, and allow to delete or upload some bans.
|
||||
*/
|
||||
|
||||
const bans = reactive({
|
||||
builder: "",
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
// Get builder data
|
||||
const dataAtt = "data-server-builder";
|
||||
const dataEl = document.querySelector(`[${dataAtt}]`);
|
||||
const data =
|
||||
dataEl && !dataEl.getAttribute(dataAtt).includes(dataAtt)
|
||||
? JSON.parse(dataEl.getAttribute(dataAtt))
|
||||
: {};
|
||||
bans.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
});
|
||||
|
||||
const builder = [];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DashboardLayout>
|
||||
<BuilderBans v-if="builder" :builder="builder" />
|
||||
</DashboardLayout>
|
||||
</template>
|
||||
11
vuejs/client/src/pages/bans/bans.js
Normal file
11
vuejs/client/src/pages/bans/bans.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import { getI18n } from "@utils/lang.js";
|
||||
import Bans from "./Bans.vue";
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
createApp(Bans)
|
||||
.use(pinia)
|
||||
.use(getI18n(["dashboard", "action", "inp", "icons", "bans"]))
|
||||
.mount("#app");
|
||||
22
vuejs/client/src/pages/bans/index.html
Normal file
22
vuejs/client/src/pages/bans/index.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="/images/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 | Bans</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='[{"type":"card","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"details":[{"key":"instances_hostname","value":"bunkerweb"},{"key":"instances_type","value":"manual"},{"key":"instances_status","value":"instances_active"}],"status":"success","title":"bunkerweb","buttons":[{"attrs":{"data-form-INSTANCE_ID":"bunkerweb","data-form-operation":"reload","data-submit-form":"true"},"text":"action_reload","color":"warning","size":"normal"},{"attrs":{"data-form-INSTANCE_ID":"bunkerweb","data-form-operation":"stop","data-submit-form":"true"},"text":"action_stop","color":"error","size":"normal"}]}}]}]'>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="bans.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import { getI18n } from "@utils/lang.js";
|
||||
import Reports from "./reports.vue";
|
||||
import Reports from "./Reports.vue";
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
|
|
|
|||
239
vuejs/tests/bans.py
Normal file
239
vuejs/tests/bans.py
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
import json
|
||||
|
||||
no_bans = []
|
||||
|
||||
|
||||
bans = [
|
||||
{
|
||||
"reason": "ui",
|
||||
"date": 1719393920,
|
||||
"ip": "127.0.0.1",
|
||||
"remain": "23 hours and 49 minutes",
|
||||
"term": "hour(s)",
|
||||
"ban_start": "26/06/2024 09:25:20",
|
||||
"ban_end": "27/06/2024 09:15:15",
|
||||
},
|
||||
{
|
||||
"reason": "ui",
|
||||
"date": 1719393920,
|
||||
"ip": "127.0.0.1",
|
||||
"remain": "23 hours and 49 minutes",
|
||||
"term": "hour(s)",
|
||||
"ban_start": "26/06/2024 09:25:20",
|
||||
"ban_end": "27/06/2024 09:15:15",
|
||||
},
|
||||
]
|
||||
# Reoder bans dict
|
||||
for ban in bans:
|
||||
ban["ip"] = ban.pop("ip")
|
||||
ban["reason"] = ban.pop("reason")
|
||||
ban["ban_start"] = ban.pop("ban_start")
|
||||
ban["ban_end"] = ban.pop("ban_end")
|
||||
ban["remain"] = ban.pop("remain")
|
||||
ban["term"] = ban.pop("term")
|
||||
|
||||
|
||||
def get_bans_filter(bans):
|
||||
|
||||
if len(bans) <= 5:
|
||||
return []
|
||||
|
||||
total_reasons = ["all"]
|
||||
total_terms = ["all"]
|
||||
|
||||
for ban in bans:
|
||||
if ban.get("reason") and ban.get("reason") not in total_reasons:
|
||||
total_reasons.append(ban.get("reason"))
|
||||
|
||||
if ban.get("term") and ban.get("term") not in total_terms:
|
||||
total_terms.append(ban.get("term"))
|
||||
|
||||
filters = []
|
||||
|
||||
filters.append(
|
||||
{
|
||||
"filter": "table",
|
||||
"filterName": "keyword",
|
||||
"type": "keyword",
|
||||
"value": "",
|
||||
"keys": ["ip", "ban_start", "ban_end"],
|
||||
"field": {
|
||||
"id": "bans-keyword",
|
||||
"value": "",
|
||||
"type": "text",
|
||||
"name": "bans-keyword",
|
||||
"label": "bans_search",
|
||||
"placeholder": "inp_keyword",
|
||||
"isClipboard": False,
|
||||
"popovers": [
|
||||
{
|
||||
"text": "bans_search_desc",
|
||||
"iconName": "info",
|
||||
},
|
||||
],
|
||||
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if len(total_reasons) > 1:
|
||||
filters.append(
|
||||
{
|
||||
"filter": "table",
|
||||
"filterName": "reason",
|
||||
"type": "select",
|
||||
"value": "all",
|
||||
"keys": ["reason"],
|
||||
"field": {
|
||||
"id": "bans-reason",
|
||||
"value": "all",
|
||||
"values": total_reasons,
|
||||
"name": "bans-reason",
|
||||
"onlyDown": True,
|
||||
"label": "bans_reason",
|
||||
"popovers": [
|
||||
{
|
||||
"text": "bans_reason_desc",
|
||||
"iconName": "info",
|
||||
},
|
||||
],
|
||||
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if len(total_terms) > 1:
|
||||
filters.append(
|
||||
{
|
||||
"filter": "table",
|
||||
"filterName": "term",
|
||||
"type": "select",
|
||||
"value": "all",
|
||||
"keys": ["term"],
|
||||
"field": {
|
||||
"id": "bans-terms",
|
||||
"value": "all",
|
||||
"values": total_terms,
|
||||
"name": "bans-terms",
|
||||
"onlyDown": True,
|
||||
"label": "bans_terms",
|
||||
"popovers": [
|
||||
{
|
||||
"text": "bans_terms_desc",
|
||||
"iconName": "info",
|
||||
},
|
||||
],
|
||||
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
|
||||
},
|
||||
},
|
||||
)
|
||||
return filters
|
||||
|
||||
|
||||
def get_reports_list(reports):
|
||||
data = []
|
||||
# loop on each dict
|
||||
for report in reports:
|
||||
item = []
|
||||
for k, v in report.items():
|
||||
item.append(
|
||||
{
|
||||
k: json.dumps(v) if isinstance(v, dict) else str(v),
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": json.dumps(v) if isinstance(v, dict) else str(v),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
data.append(item)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_reports_details(details):
|
||||
return {
|
||||
"type": "card",
|
||||
"containerColumns": {"pc": 4, "tablet": 6, "mobile": 12},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {"title": "dashboard_details"},
|
||||
},
|
||||
{
|
||||
"type": "ListPairs",
|
||||
"data": {
|
||||
"pairs": [
|
||||
{"key": "reports_total", "value": details.get("total_reports")},
|
||||
{"key": "reports_top_status", "value": details.get("top_code")},
|
||||
{
|
||||
"key": "reports_top_reason",
|
||||
"value": details.get("top_reason"),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def reports_builder(reports, details=None):
|
||||
|
||||
if not reports:
|
||||
return [
|
||||
{
|
||||
"type": "void",
|
||||
"widgets": [
|
||||
{"type": "MessageUnmatch", "data": {"text": "reports_not_found"}}
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
details = get_reports_details(details)
|
||||
|
||||
filters = get_bans_filter(reports)
|
||||
reports_list = get_reports_list(reports)
|
||||
|
||||
reports_table = {
|
||||
"type": "card",
|
||||
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {"title": "reports_title"},
|
||||
},
|
||||
{
|
||||
"type": "Table",
|
||||
"data": {
|
||||
"title": "reports_table_title",
|
||||
"minWidth": "xl",
|
||||
"header": [
|
||||
"reports_table_date",
|
||||
"reports_table_ip",
|
||||
"reports_table_country",
|
||||
"reports_table_method",
|
||||
"reports_table_url",
|
||||
"reports_table_status_code",
|
||||
"reports_table_cache_user_agent",
|
||||
"reports_table_reason",
|
||||
"reports_table_data",
|
||||
],
|
||||
"positions": [1, 1, 1, 1, 2, 1, 2, 1, 2],
|
||||
"items": reports_list,
|
||||
"filters": filters,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
builder = [details, reports_table]
|
||||
|
||||
return builder
|
||||
|
||||
|
||||
# output = reports_builder(reports)
|
||||
output = reports_builder(no_bans)
|
||||
|
||||
# store on a file
|
||||
with open("reports.json", "w") as f:
|
||||
json.dump(output, f, indent=4)
|
||||
Loading…
Reference in a new issue