From 8c05d324d3ab0744c96091ac4f8403bc401503d2 Mon Sep 17 00:00:00 2001 From: Alexandr Bogomyakov Date: Mon, 18 Mar 2024 16:07:48 +0200 Subject: [PATCH 1/4] redesign and k8s support --- k8s.py | 34 ++++++++++++++ main.py | 36 +++++++++++++++ requirements.txt | 1 + static/layout.css | 9 +++- templates/base.html | 29 ++++++------ templates/index.html | 108 ++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 k8s.py diff --git a/k8s.py b/k8s.py new file mode 100644 index 0000000..da263c7 --- /dev/null +++ b/k8s.py @@ -0,0 +1,34 @@ +import base64 +import json +import logging +from kubernetes import client, config +from kubernetes.client.rest import ApiException + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + datefmt="%d-%m-%Y %H:%M:%S", +) + +log = logging.getLogger("OutFleet.k8s") +file_handler = logging.FileHandler("sync.log") +file_handler.setLevel(logging.DEBUG) +formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +file_handler.setFormatter(formatter) +log.addHandler(file_handler) + +config.load_incluster_config() + +v1 = client.CoreV1Api() + +NAMESPACE = "" + +log.info("Checking for Kubernetes environment") +try: + with open("/var/run/secrets/kubernetes.io/serviceaccount/namespace") as f: + NAMESPACE = f.read().strip() +except IOError: + log.info("Kubernetes environment not detected") + pass \ No newline at end of file diff --git a/main.py b/main.py index d3cde2e..88135a5 100644 --- a/main.py +++ b/main.py @@ -6,10 +6,13 @@ import string import argparse import uuid + +import k8s from flask import Flask, render_template, request, url_for, redirect from flask_cors import CORS from lib import Server + logging.getLogger("werkzeug").setLevel(logging.ERROR) logging.basicConfig( @@ -34,10 +37,17 @@ parser.add_argument( default="/usr/local/etc/outfleet/config.yaml", help="Config file location", ) +parser.add_argument( + "--k8s", + default=False, + action="store_true", + help="Kubernetes Outline server discovery", +) args = parser.parse_args() CFG_PATH = args.config SERVERS = list() +BROKEN_SERVERS = list() CLIENTS = dict() VERSION = '3' HOSTNAME = "" @@ -54,12 +64,30 @@ def random_string(length=64): return "".join(random.choice(letters) for i in range(length)) +def get_config(): + if not args.k8s: + try: + with open(CFG_PATH, "r") as file: + config = yaml.safe_load(file) + except: + try: + with open(CFG_PATH, "w"): + pass + except Exception as exp: + log.error(f"Couldn't create config. {exp}") + else: + pass + + def update_state(): global SERVERS global CLIENTS + global BROKEN_SERVERS global HOSTNAME + SERVERS = list() + BROKEN_SERVERS = list() CLIENTS = dict() config = dict() try: @@ -90,6 +118,11 @@ def update_state(): local_server_id, ) except Exception as e: + BROKEN_SERVERS.append({ + "config": server_config, + "error": e, + "id": local_server_id + }) log.warning("Can't access server: %s - %s", server_config["url"], e) CLIENTS = config.get("clients", dict()) @@ -98,13 +131,16 @@ def update_state(): @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "GET": + #if request.args.get("broken") == True: return render_template( "index.html", SERVERS=SERVERS, VERSION=VERSION, + BROKEN_SERVERS=BROKEN_SERVERS, nt=request.args.get("nt"), nl=request.args.get("nl"), selected_server=request.args.get("selected_server"), + broken=request.args.get("broken", False), add_server=request.args.get("add_server", None), format_timestamp=format_timestamp, ) diff --git a/requirements.txt b/requirements.txt index 87427de..c6bef34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ outline-vpn-api +kubernetes PyYAML>=6.0.1 Flask>=2.3.3 flask-cors \ No newline at end of file diff --git a/static/layout.css b/static/layout.css index bf2bb28..48d442a 100644 --- a/static/layout.css +++ b/static/layout.css @@ -4,6 +4,7 @@ */ body { color: #333; + word-wrap: break-word; } @@ -22,8 +23,8 @@ a { border-radius: 4px; } .delete-button { - background: #a20c0c; - border: 2px solid #310404; + background: #9d2c2c; + border: 1px solid #480b0b; color: #ffffff; } @@ -158,6 +159,10 @@ a { .server-item-unread { border-left: 6px solid #1b98f8; } +.server-item-broken { + border-left: 6px solid #880d06; +} + .server-item:hover { background: #d1d0d0; } diff --git a/templates/base.html b/templates/base.html index 8a86b18..e0aa12b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -15,11 +15,13 @@ .content { padding: 10px; } + .form-field { margin: 5px; width: 100%; } + @@ -79,7 +81,8 @@
{% endfor %} + {% for broken_server in BROKEN_SERVERS %} + {% set config = broken_server["config"] %} + {% set error = broken_server["error"] %} +
+
+
{{ config.get("name", "None") }}
+

API {{ '/'.join(config.get("url", "None").split('/')[0:-1]).split("://")[1] }} +

+

Client Port: N/D

+

Hostname: N/D

+

Traffic: N/D

+

Version: N/D

+

+ {{ config.get("comment", "None") }} + +

+
+ {{ error }} +
+
+
+ {% endfor %}
+ @@ -71,7 +93,9 @@ {% else %} {% set server = SERVERS[selected_server|int] %} {% endif %} +
+ {% if not is_broken %}
@@ -81,7 +105,6 @@ v.{{server.info()["version"]}} {{server.info()["local_server_id"]}}

-
{% set ns = namespace(total_bytes=0) %} @@ -122,19 +145,19 @@
-
-
Created {{format_timestamp(server.info()['created_timestamp_ms']) }}
- +

Share anonymous metrics

+ {% else %} + + {% for server in BROKEN_SERVERS %} + {% if server["id"] == selected_server %} + {% set config_block = server["config"] %} + {% endif %} + {% endfor %} + {{config_block}} {{id}} +
+
+
+
+

{{config_block["name"]}}

+
+
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ + + + +
+ +
+
+
+ {% endif %} {% endif %} From 5109de5c9ad21129156fefb6ebf72af0cb1517c4 Mon Sep 17 00:00:00 2001 From: Alexandr Bogomyakov Date: Mon, 18 Mar 2024 18:53:38 +0200 Subject: [PATCH 2/4] k8s discovery works --- .github/workflows/main.yml | 0 .gitignore | 3 +- .idea/.gitignore | 0 .idea/OutlineFleet.iml | 0 .../inspectionProfiles/profiles_settings.xml | 0 .idea/misc.xml | 0 .idea/modules.xml | 0 .idea/vcs.xml | 0 .vscode/extensions.json | 0 Dockerfile | 0 LICENSE | 0 README.md | 0 buildx.yaml | 0 img/servers.png | Bin k8s.py | 47 ++++++++- lib.py | 45 ++++++++- main.py | 94 +++--------------- requirements.txt | 0 static/layout.css | 0 static/pure.css | 0 templates/base.html | 0 templates/clients.html | 0 templates/index.html | 0 templates/sync.html | 0 24 files changed, 101 insertions(+), 88 deletions(-) mode change 100644 => 100755 .github/workflows/main.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .idea/.gitignore mode change 100644 => 100755 .idea/OutlineFleet.iml mode change 100644 => 100755 .idea/inspectionProfiles/profiles_settings.xml mode change 100644 => 100755 .idea/misc.xml mode change 100644 => 100755 .idea/modules.xml mode change 100644 => 100755 .idea/vcs.xml mode change 100644 => 100755 .vscode/extensions.json mode change 100644 => 100755 Dockerfile mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 buildx.yaml mode change 100644 => 100755 img/servers.png mode change 100644 => 100755 k8s.py mode change 100644 => 100755 lib.py mode change 100644 => 100755 main.py mode change 100644 => 100755 requirements.txt mode change 100644 => 100755 static/layout.css mode change 100644 => 100755 static/pure.css mode change 100644 => 100755 templates/base.html mode change 100644 => 100755 templates/clients.html mode change 100644 => 100755 templates/index.html mode change 100644 => 100755 templates/sync.html diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index a51b144..105f280 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ config.yaml __pycache__/ sync.log main.py -.vscode/launch.json +.idea/* +.vscode/* *.swp *.swo *.swn diff --git a/.idea/.gitignore b/.idea/.gitignore old mode 100644 new mode 100755 diff --git a/.idea/OutlineFleet.iml b/.idea/OutlineFleet.iml old mode 100644 new mode 100755 diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml old mode 100644 new mode 100755 diff --git a/.idea/misc.xml b/.idea/misc.xml old mode 100644 new mode 100755 diff --git a/.idea/modules.xml b/.idea/modules.xml old mode 100644 new mode 100755 diff --git a/.idea/vcs.xml b/.idea/vcs.xml old mode 100644 new mode 100755 diff --git a/.vscode/extensions.json b/.vscode/extensions.json old mode 100644 new mode 100755 diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/buildx.yaml b/buildx.yaml old mode 100644 new mode 100755 diff --git a/img/servers.png b/img/servers.png old mode 100644 new mode 100755 diff --git a/k8s.py b/k8s.py old mode 100644 new mode 100755 index da263c7..743d489 --- a/k8s.py +++ b/k8s.py @@ -1,5 +1,6 @@ import base64 import json +import yaml import logging from kubernetes import client, config from kubernetes.client.rest import ApiException @@ -19,16 +20,58 @@ formatter = logging.Formatter( file_handler.setFormatter(formatter) log.addHandler(file_handler) +def write_config(config): + config_map = client.V1ConfigMap( + api_version="v1", + kind="ConfigMap", + metadata=client.V1ObjectMeta( + name=f"config-outfleet", + labels={ + "app": "outfleet", + } + ), + data={"config.yaml": yaml.dump(config)} + ) + try: + api_response = v1.create_namespaced_config_map( + namespace=NAMESPACE, + body=config_map, + ) + except ApiException as e: + api_response = v1.patch_namespaced_config_map( + name="config-outfleet", + namespace=NAMESPACE, + body=config_map, + ) + config.load_incluster_config() v1 = client.CoreV1Api() -NAMESPACE = "" +NAMESPACE = False +SERVERS = list() +CONFIG = None log.info("Checking for Kubernetes environment") try: with open("/var/run/secrets/kubernetes.io/serviceaccount/namespace") as f: NAMESPACE = f.read().strip() + log.info(f"Found Kubernetes environment. Namespace {NAMESPACE}") except IOError: log.info("Kubernetes environment not detected") - pass \ No newline at end of file + pass + +# config = v1.list_namespaced_config_map(NAMESPACE, label_selector="app=outfleet").items["data"]["config.yaml"] +try: + CONFIG = yaml.safe_load(v1.read_namespaced_config_map(name="config-outfleet", namespace=NAMESPACE).data['config.yaml']) + log.info(f"ConfigMap config.yaml loaded from Kubernetes API. Servers: {len(CONFIG['servers'])}, Clients: {len(CONFIG['clients'])}") +except ApiException as e: + log.warning(f"ConfigMap not found. Fisrt run?") + +#servers = v1.list_namespaced_secret(NAMESPACE, label_selector="app=shadowbox") + +if not CONFIG: + log.info(f"Creating new ConfigMap [config-outfleet]") + write_config({"clients": [], "servers": [], "ui_hostname": "accessible-address.com"}) + CONFIG = yaml.safe_load(v1.read_namespaced_config_map(name="config-outfleet", namespace=NAMESPACE).data['config.yaml']) + diff --git a/lib.py b/lib.py old mode 100644 new mode 100755 index 48eab65..47e1054 --- a/lib.py +++ b/lib.py @@ -1,7 +1,10 @@ +import argparse import logging from typing import TypedDict, List from outline_vpn.outline_vpn import OutlineKey, OutlineVPN import yaml +import k8s + logging.basicConfig( level=logging.INFO, @@ -9,6 +12,42 @@ logging.basicConfig( datefmt="%d-%m-%Y %H:%M:%S", ) +log = logging.getLogger(f'OutFleet.lib') +parser = argparse.ArgumentParser() +parser.add_argument( + "-c", + "--config", + default="/usr/local/etc/outfleet/config.yaml", + help="Config file location", +) + +args = parser.parse_args() +def get_config(): + if not k8s.NAMESPACE: + try: + with open(args.config, "r") as file: + config = yaml.safe_load(file) + except: + try: + with open(args.config, "w"): + pass + except Exception as exp: + log.error(f"Couldn't create config. {exp}") + return None + return config + else: + return k8s.CONFIG + +def write_config(config): + if not k8s.NAMESPACE: + try: + with open(args.config, "w") as file: + yaml.safe_dump(config, file) + except Exception as e: + log.error(f"Couldn't write Outfleet config: {e}") + else: + k8s.write_config(config) + class ServerDict(TypedDict): server_id: str @@ -114,13 +153,11 @@ class Server: config.get("hostname_for_access_keys"), ) if config.get("comment"): - with open(CFG_PATH, "r") as file: - config_file = yaml.safe_load(file) or {} + config_file = get_config() config_file["servers"][self.data["local_server_id"]]["comment"] = config.get( "comment" ) - with open(CFG_PATH, "w") as file: - yaml.safe_dump(config_file, file) + write_config(config_file) self.log.info( "Changed %s comment to '%s'", self.data["local_server_id"], diff --git a/main.py b/main.py old mode 100644 new mode 100755 index 88135a5..bec2e8c --- a/main.py +++ b/main.py @@ -10,7 +10,7 @@ import uuid import k8s from flask import Flask, render_template, request, url_for, redirect from flask_cors import CORS -from lib import Server +from lib import Server, write_config, get_config, args logging.getLogger("werkzeug").setLevel(logging.ERROR) @@ -30,22 +30,9 @@ formatter = logging.Formatter( file_handler.setFormatter(formatter) log.addHandler(file_handler) -parser = argparse.ArgumentParser() -parser.add_argument( - "-c", - "--config", - default="/usr/local/etc/outfleet/config.yaml", - help="Config file location", -) -parser.add_argument( - "--k8s", - default=False, - action="store_true", - help="Kubernetes Outline server discovery", -) -args = parser.parse_args() -CFG_PATH = args.config +CFG_PATH = args.config +NAMESPACE = k8s.NAMESPACE SERVERS = list() BROKEN_SERVERS = list() CLIENTS = dict() @@ -64,20 +51,6 @@ def random_string(length=64): return "".join(random.choice(letters) for i in range(length)) -def get_config(): - if not args.k8s: - try: - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) - except: - try: - with open(CFG_PATH, "w"): - pass - except Exception as exp: - log.error(f"Couldn't create config. {exp}") - else: - pass - def update_state(): @@ -89,16 +62,8 @@ def update_state(): SERVERS = list() BROKEN_SERVERS = list() CLIENTS = dict() - config = dict() - try: - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) - except: - try: - with open(CFG_PATH, "w"): - pass - except Exception as exp: - log.error(f"Couldn't create config. {exp}") + config = get_config() + if config: HOSTNAME = config.get("ui_hostname", "my-own-SSL-ENABLED-domain.com") @@ -164,13 +129,6 @@ def index(): @app.route("/clients", methods=["GET", "POST"]) def clients(): - # {% for server in SERVERS %} - # {% for key in server.data["keys"] %} - # {% if key.name == client['name'] %} - # ssconf://{{ dynamic_hostname }}/dynamic/{{server.info()['name']}}/{{selected_client}}#{{server.info()['comment']}} - # {% endif %} - # {% endfor %} - # {% endfor %} if request.method == "GET": return render_template( "clients.html", @@ -184,22 +142,13 @@ def clients(): format_timestamp=format_timestamp, dynamic_hostname=HOSTNAME, ) - # else: - # server = request.form['server_id'] - # server = next((item for item in SERVERS if item.info()["server_id"] == server), None) - # server.apply_config(request.form) - # update_state() - # return redirect( - # url_for('index', nt="Updated Outline VPN Server", selected_server=request.args.get('selected_server'))) @app.route("/add_server", methods=["POST"]) def add_server(): if request.method == "POST": try: - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) or {} - + config = get_config() servers = config.get("servers", dict()) local_server_id = str(uuid.uuid4()) @@ -217,16 +166,7 @@ def add_server(): "cert": request.form["cert"], } config["servers"] = servers - try: - with open(CFG_PATH, "w") as file: - yaml.safe_dump(config, file) - except Exception as e: - return redirect( - url_for( - "index", nt=f"Couldn't write Outfleet config: {e}", nl="error" - ) - ) - + write_config(config) log.info("Added server: %s", new_server.data["name"]) update_state() return redirect(url_for("index", nt="Added Outline VPN Server")) @@ -240,8 +180,7 @@ def add_server(): @app.route("/del_server", methods=["POST"]) def del_server(): if request.method == "POST": - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) or {} + config = get_config() local_server_id = request.form.get("local_server_id") server_name = None @@ -254,9 +193,7 @@ def del_server(): client_config["servers"].remove(local_server_id) except ValueError as e: pass - - with open(CFG_PATH, "w") as file: - yaml.safe_dump(config, file) + write_config(config) log.info("Deleting server %s [%s]", server_name, request.form.get("local_server_id")) update_state() return redirect(url_for("index", nt=f"Server {server_name} has been deleted")) @@ -265,8 +202,7 @@ def del_server(): @app.route("/add_client", methods=["POST"]) def add_client(): if request.method == "POST": - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) or {} + config = get_config() clients = config.get("clients", dict()) user_id = request.form.get("user_id", random_string()) @@ -277,8 +213,7 @@ def add_client(): "servers": request.form.getlist("servers"), } config["clients"] = clients - with open(CFG_PATH, "w") as file: - yaml.safe_dump(config, file) + write_config(config) log.info("Client %s updated", request.form.get("name")) for server in SERVERS: @@ -340,9 +275,7 @@ def add_client(): @app.route("/del_client", methods=["POST"]) def del_client(): if request.method == "POST": - with open(CFG_PATH, "r") as file: - config = yaml.safe_load(file) or {} - + config = get_config() clients = config.get("clients", dict()) user_id = request.form.get("user_id") if user_id in clients: @@ -359,8 +292,7 @@ def del_client(): server.delete_key(client.key_id) config["clients"].pop(user_id) - with open(CFG_PATH, "w") as file: - yaml.safe_dump(config, file) + write_config(config) log.info("Deleting client %s", request.form.get("name")) update_state() return redirect(url_for("clients", nt="User has been deleted")) diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 diff --git a/static/layout.css b/static/layout.css old mode 100644 new mode 100755 diff --git a/static/pure.css b/static/pure.css old mode 100644 new mode 100755 diff --git a/templates/base.html b/templates/base.html old mode 100644 new mode 100755 diff --git a/templates/clients.html b/templates/clients.html old mode 100644 new mode 100755 diff --git a/templates/index.html b/templates/index.html old mode 100644 new mode 100755 diff --git a/templates/sync.html b/templates/sync.html old mode 100644 new mode 100755 From 715494fa5f774269ed234447aef4e14e8eb8cd2b Mon Sep 17 00:00:00 2001 From: Alexandr Bogomyakov Date: Mon, 18 Mar 2024 19:06:10 +0200 Subject: [PATCH 3/4] Restore UI --- templates/base.html | 178 ++++++++++----------- templates/clients.html | 289 ++++++++++++++++----------------- templates/index.html | 351 ++++++++++++++--------------------------- templates/sync.html | 39 ++--- 4 files changed, 347 insertions(+), 510 deletions(-) mode change 100755 => 100644 templates/base.html mode change 100755 => 100644 templates/clients.html mode change 100755 => 100644 templates/index.html mode change 100755 => 100644 templates/sync.html diff --git a/templates/base.html b/templates/base.html old mode 100755 new mode 100644 index e0aa12b..8502e96 --- a/templates/base.html +++ b/templates/base.html @@ -1,113 +1,93 @@ - - {% block title %}Dashboard{% endblock %} - - - - - - - - + {% block title %}Dashboard{% endblock %} + + + -
-
-
- -
-
-
-
- {% block content %}{% endblock %} +
+ + {% block content %}{% endblock %} +
+ + + +{% if nt %} + +{% endif %} - - \ No newline at end of file + diff --git a/templates/clients.html b/templates/clients.html old mode 100755 new mode 100644 index e0fc40a..97d8ef5 --- a/templates/clients.html +++ b/templates/clients.html @@ -2,190 +2,173 @@ {% block content %} -
-
+
+

Clients

-
-
- + -
-
{% for client, values in CLIENTS.items() %} -
-
+
+
{{ values["name"] }}
-

Allowed {{ values["servers"]|length }} server{% if values["servers"]|length >1 - %}s{%endif%}

+

Allowed {{ values["servers"]|length }} server{% if values["servers"]|length >1 %}s{%endif%}

{% endfor %} - +
+
+ + +
+
-
- {% if add_client %} -
-
-

Add new client

+{% if add_client %} +
+
+
+

Add new client

+
-
-
+
- - - {% for server in SERVERS %} - - {% endfor %} - +
+
+ +
+
+ +
+
+ {% for server in SERVERS %} + + + {% endfor %} + +
+ +
+
- {% endif %} - - {% if selected_client and not add_client %} - {% set client = CLIENTS[selected_client] %} -
-
-
-
-

{{client['name']}}

-

{{ selected_client }}

- {% if client['comment'] != "" %}

{{ client['comment'] }}

{% endif %} -
-
-
-
-
+{% endif %} -
-
-
-
- - -
-
- -
- +{% if selected_client and not add_client %} + {% set client = CLIENTS[selected_client] %} -
-

Allow access to:

- {% for server in SERVERS %} - +
+
+
+

{{client['name']}}

+

{{ client['comment'] }}

+

id {{ selected_client }}

- {% endfor %} - -
- -
-
-
- - - - -
-
-
-
-

Invite text

+
+
+
+
+
+ + +
+
+ +
+ - - -
-
-
- -
- +{%- endfor -%}
+
+
+
+

Dynamic Access Keys

+ + + + + + + + + {% for server in SERVERS %} + {% if server.info()['local_server_id'] in client['servers'] %} + + + + + {% endif %} + {% endfor %} + +
ServerDynamic
{{ server.info()['name'] }} +

{% for key in server.data["keys"] %}{% if key.key_id == client['name'] %}ssconf://{{ dynamic_hostname }}/dynamic/{{server.info()['name']}}/{{selected_client}}#{{server.info()['comment']}}{% endif %}{% endfor %}

+
-
-
-

Dynamic Access Keys

- - - - - - - - - {% for server in SERVERS %} - {% if server.info()['local_server_id'] in client['servers'] %} - - - - - {% endif %} - {% endfor %} - -
ServerDynamic
{{ server.info()['name'] }} - {% for key in server.data["keys"] %}{% if key.key_id == client['name'] %}ssconf://{{ - dynamic_hostname - }}/dynamic/{{server.info()['name']}}/{{selected_client}}#{{server.info()['comment']}}{% - endif %}{% endfor %} -
-
-
-

SS Links

- - - - - - - - - {% for server in SERVERS %} - {% if server.info()['local_server_id'] in client['servers'] %} - - - - - {% endif %} - {% endfor %} - -
ServerSSlink
{{ server.info()['name'] }} - {% for key in server.data["keys"] %}{% if key.key_id == client['name'] %}{{ - key.access_url }}{% endif %}{% endfor %} -
-
+
+

SS Links

+ + + + + + + + + {% for server in SERVERS %} + {% if server.info()['local_server_id'] in client['servers'] %} + + + + + {% endif %} + {% endfor %} + +
ServerSSlink
{{ server.info()['name'] }} +
{% for key in server.data["keys"] %}{% if key.key_id == client['name'] %}{{ key.access_url }}{% endif %}{% endfor %}
+
- {% endif %} -
-{% endblock %} \ No newline at end of file +
+
+ + + + + +
+
+{% endif %} + +{% endblock %} diff --git a/templates/index.html b/templates/index.html old mode 100755 new mode 100644 index 9afc047..3628a0e --- a/templates/index.html +++ b/templates/index.html @@ -1,261 +1,150 @@ {% extends "base.html" %} {% block content %} -
-
-
-

Servers

-
- {% for server in SERVERS %} + +
+
+

Servers

+
+ {% for server in SERVERS %} {% set list_ns = namespace(total_bytes=0) %} {% for key in server.data["keys"] %} - {% if key.used_bytes %} - {% set list_ns.total_bytes = list_ns.total_bytes + key.used_bytes %} - {% endif %} + {% if key.used_bytes %} + {% set list_ns.total_bytes = list_ns.total_bytes + key.used_bytes %} + {% endif %} {% endfor %} -
-
-
{{ server.info()["name"] }}
-

API {{ '/'.join(server.info()["url"].split('/')[0:-1]).split("://")[1] }}

-

Client Port: {{ server.info()["port_for_new_access_keys"] }}

-

Hostname: {{ server.info()["hostname_for_access_keys"] }}

-

Traffic: {{ list_ns.total_bytes | filesizeformat }}

-

Version: {{ server.info()["version"] }}

-

- {{ server.info()["comment"] }} -

-
-
- {% endfor %} - {% for broken_server in BROKEN_SERVERS %} - {% set config = broken_server["config"] %} - {% set error = broken_server["error"] %} -
-
-
{{ config.get("name", "None") }}
-

API {{ '/'.join(config.get("url", "None").split('/')[0:-1]).split("://")[1] }} -

-

Client Port: N/D

-

Hostname: N/D

-

Traffic: N/D

-

Version: N/D

-

- {{ config.get("comment", "None") }} - -

-
- {{ error }} -
-
-
- {% endfor %} -
-
- + -
+
+
+
{{ server.info()["name"] }}
+

{{ '/'.join(server.info()["url"].split('/')[0:-1]) }}

+

Port {{ server.info()["port_for_new_access_keys"] }}

+

Hostname {{ server.info()["hostname_for_access_keys"] }}

+

Traffic: {{ list_ns.total_bytes | filesizeformat }}

+

v.{{ server.info()["version"] }}

+

+ {{ server.info()["comment"] }} +

+ {% endfor %} +
+
+ + +
+
-
- {% if add_server %} -
-
+
+ +{% if add_server %} +
+
+

Add new server

-
-
-
-
- -
-
- -
-
- -
+ +
+
+
+
- -
- -
+
+ +
+
+ +
+
+ + +
+
+{% endif %} - {% endif %} - {% if SERVERS|length != 0 and not add_server %} +{% if SERVERS|length != 0 and not add_server %} {% if selected_server is none %} - {% set server = SERVERS[0] %} + {% set server = SERVERS[0] %} {% else %} - {% set server = SERVERS[selected_server|int] %} + {% set server = SERVERS[selected_server|int] %} {% endif %} - -
- {% if not is_broken %} -
-
-
-
-

{{server.info()["name"]}}

-

- v.{{server.info()["version"]}} {{server.info()["local_server_id"]}} -

-
+
+
+
+
+

{{server.info()["name"]}}

+

+ v.{{server.info()["version"]}} {{server.info()["local_server_id"]}} +

- {% set ns = namespace(total_bytes=0) %} - {% for key in SERVERS[selected_server|int].data["keys"] %} +
+ + {% set ns = namespace(total_bytes=0) %} + {% for key in SERVERS[selected_server|int].data["keys"] %} {% if key.used_bytes %} - {% set ns.total_bytes = ns.total_bytes + key.used_bytes %} + {% set ns.total_bytes = ns.total_bytes + key.used_bytes %} {% endif %} - {% endfor %} -
-

Clients: {{ server.info()['keys']|length }}

-

Total traffic: {{ ns.total_bytes | filesizeformat }}

-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- Created {{format_timestamp(server.info()['created_timestamp_ms']) }} -
- -
-

Share anonymous metrics

- - - -
-
-
- - - - -
- + {% endfor %} +
+

Clients: {{ server.info()['keys']|length }}

+

Total traffic: {{ ns.total_bytes | filesizeformat }}

+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+

Share anonymous metrics

+ + + +
+
+
+ + + +
+
- {% else %} - - {% for server in BROKEN_SERVERS %} - {% if server["id"] == selected_server %} - {% set config_block = server["config"] %} - {% endif %} - {% endfor %} - {{config_block}} {{id}} -
-
-
-
-

{{config_block["name"]}}

-
-
-
-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- -
-
-
-
- - - - -
- -
-
-
- {% endif %}
- {% endif %} -
-{% endblock %} \ No newline at end of file +{% endif %} + +{% endblock %} diff --git a/templates/sync.html b/templates/sync.html old mode 100755 new mode 100644 index b38a0d7..292cbf5 --- a/templates/sync.html +++ b/templates/sync.html @@ -1,32 +1,17 @@ -{% extends "base.html" %} - -{% block content %} - - - - - - - - - -

Last logs

+

Last sync log

- -

Also wipe ALL keys on ALL servers? Use in case of inconsistency.

- - - -
+

Wipe ALL keys on ALL servers?

+ + + + -
-    
+
+    
 {% for line in lines %}{{ line }}{% endfor %}
     
 
- -{% endblock %} \ No newline at end of file From c065af234937f4c6c69886431f33ba7381317404 Mon Sep 17 00:00:00 2001 From: Alexandr Bogomyakov Date: Mon, 18 Mar 2024 19:09:58 +0200 Subject: [PATCH 4/4] Another shit --- .idea/.gitignore | 3 --- .idea/OutlineFleet.iml | 13 ------------- .idea/inspectionProfiles/profiles_settings.xml | 6 ------ .idea/misc.xml | 10 ---------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ .vscode/extensions.json | 6 ------ 7 files changed, 52 deletions(-) delete mode 100755 .idea/.gitignore delete mode 100755 .idea/OutlineFleet.iml delete mode 100755 .idea/inspectionProfiles/profiles_settings.xml delete mode 100755 .idea/misc.xml delete mode 100755 .idea/modules.xml delete mode 100755 .idea/vcs.xml delete mode 100755 .vscode/extensions.json diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100755 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/OutlineFleet.iml b/.idea/OutlineFleet.iml deleted file mode 100755 index 0bad138..0000000 --- a/.idea/OutlineFleet.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100755 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100755 index 455776e..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100755 index 67f92ec..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100755 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100755 index f137989..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "recommendations": [ - "tht13.python", - "ms-python.python" - ] -} \ No newline at end of file