mirror of
https://github.com/WGDashboard/WGDashboard-PRW.git
synced 2026-08-04 06:52:58 +00:00
chore: add code update
This commit is contained in:
+2
-2
@@ -25,10 +25,10 @@ log_level = DEBUG
|
|||||||
|
|
||||||
[account]
|
[account]
|
||||||
username = dselen
|
username = dselen
|
||||||
password = $2b$12$LId4p4WP3N0RLFi/TjNxseA1U.yybg2bJ8ufvcbpclUxckEX6OH.y
|
password = $2b$12$0dvZY7mNbEcjfJI09AqxbeKYhBwoNwBrD4OQNhlJ3HqXoAbZmhNFq
|
||||||
enable_totp = False
|
enable_totp = False
|
||||||
totp_verified = False
|
totp_verified = False
|
||||||
totp_key = NY7VFZFYIUM7FUZCDW7UMXQ7DMGGLSJU
|
totp_key = ON75CRNI7MGTA33PTHTQEZVXB5JKCEYK
|
||||||
|
|
||||||
[other]
|
[other]
|
||||||
welcome_session = False
|
welcome_session = False
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ from .locale import localeman
|
|||||||
from ..database.functions import functions
|
from ..database.functions import functions
|
||||||
from ..config.config import config
|
from ..config.config import config
|
||||||
|
|
||||||
|
from ..utilities.utilities import utilities
|
||||||
|
from ..utilities.system_status import system_status
|
||||||
|
|
||||||
routes = flask.Blueprint("routes", __name__)
|
routes = flask.Blueprint("routes", __name__)
|
||||||
|
|
||||||
white_list = [
|
white_list = [
|
||||||
@@ -158,19 +161,9 @@ def api_authenticate():
|
|||||||
return make_resp_obj(False, error_msg, {"status": False}, 401)
|
return make_resp_obj(False, error_msg, {"status": False}, 401)
|
||||||
|
|
||||||
if totp_enabled:
|
if totp_enabled:
|
||||||
return make_resp_obj(
|
return make_resp_obj(False, "Sorry, your username, password or OTP is incorrect.", {}, 401)
|
||||||
False,
|
|
||||||
"Sorry, your username, password or OTP is incorrect.",
|
|
||||||
{},
|
|
||||||
401
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return make_resp_obj(
|
return make_resp_obj(False, "Sorry, your username or password is incorrect.", {}, 401)
|
||||||
False,
|
|
||||||
"Sorry, your username or password is incorrect.",
|
|
||||||
{},
|
|
||||||
401
|
|
||||||
)
|
|
||||||
|
|
||||||
@routes.route('/')
|
@routes.route('/')
|
||||||
def index_handler():
|
def index_handler():
|
||||||
@@ -216,6 +209,11 @@ def api_retrieve_dashboard_theme():
|
|||||||
|
|
||||||
return make_resp_obj(True, "", config_server.get("wgdashboard_theme"), 200)
|
return make_resp_obj(True, "", config_server.get("wgdashboard_theme"), 200)
|
||||||
|
|
||||||
|
@routes.route('/api/getDashboardUpdate')
|
||||||
|
def api_retrieve_dashboard_update():
|
||||||
|
utilities.update_available()
|
||||||
|
return make_resp_obj()
|
||||||
|
|
||||||
@routes.route('/api/getDashboardConfiguration')
|
@routes.route('/api/getDashboardConfiguration')
|
||||||
def api_retrieve_dashboard_config():
|
def api_retrieve_dashboard_config():
|
||||||
return make_resp_obj(data=flask.current_app.wgd_config)
|
return make_resp_obj(data=flask.current_app.wgd_config)
|
||||||
@@ -231,11 +229,31 @@ def api_totp_status():
|
|||||||
|
|
||||||
return make_resp_obj(True, "", data, 200)
|
return make_resp_obj(True, "", data, 200)
|
||||||
|
|
||||||
|
@routes.route('/api/getWireguardConfigurations')
|
||||||
|
def api_retrieve_wireguard_configurations():
|
||||||
|
ok, config_server = config.filter(flask.current_app.wgd_config, 'SERVER')
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to filter the config in-memory")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
if "wg_conf_path" not in config_server:
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
wireguard_path = config_server.get('wg_conf_path', '/etc/wireguard')
|
||||||
|
if os.path.exists(wireguard_path):
|
||||||
|
present_confs = os.listdir(wireguard_path)
|
||||||
|
present_confs.sort()
|
||||||
|
|
||||||
|
log.info(present_confs)
|
||||||
|
|
||||||
|
return make_resp_obj(True, 'Wireguard', {}, 200)
|
||||||
|
|
||||||
|
@routes.route('/api/systemStatus')
|
||||||
|
def api_system_status():
|
||||||
|
status = system_status()
|
||||||
|
return make_resp_obj(True, "", status.to_json(), 200)
|
||||||
|
|
||||||
@routes.route('/health', methods=["GET"])
|
@routes.route('/health', methods=["GET"])
|
||||||
@routes.route('/healthz', methods=["GET"])
|
@routes.route('/healthz', methods=["GET"])
|
||||||
def health_handler():
|
def health_handler():
|
||||||
return make_resp_obj(True,
|
return make_resp_obj(True, "Health Endpoint", {"status": "ok"}, 200)
|
||||||
"Health Endpoint",
|
|
||||||
{"status": "ok"},
|
|
||||||
200
|
|
||||||
)
|
|
||||||
@@ -72,6 +72,42 @@ def api_welcome_get_totp():
|
|||||||
log.error("failed to update the key in the configuration file")
|
log.error("failed to update the key in the configuration file")
|
||||||
return make_resp_obj(False, 'Internal error', {}, 500)
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
# Very important to also refresh the config in-memory
|
||||||
|
ok, flask.current_app.wgd_config = config.read()
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to refresh the in-memory configuration")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
return make_resp_obj(True, '', pyotp.totp.TOTP(totp_key).provisioning_uri(issuer_name="WGDashboard Admin"))
|
return make_resp_obj(True, '', pyotp.totp.TOTP(totp_key).provisioning_uri(issuer_name="WGDashboard Admin"))
|
||||||
|
|
||||||
return make_resp_obj(False, 'Internal error', {}, 500)
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
@routes_welcome.route('/api/Welcome_VerifyTotpLink', methods=["POST"])
|
||||||
|
def api_welcome_verify_totp():
|
||||||
|
ok, config_account = config.filter(flask.current_app.wgd_config, 'ACCOUNT')
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to filter the config in-memory")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
req_data = flask.request.get_json()
|
||||||
|
totp_code = pyotp.TOTP(config_account['totp_key'], interval=30).now()
|
||||||
|
|
||||||
|
totp_match = totp_code == req_data['totp']
|
||||||
|
if totp_match:
|
||||||
|
ok = config.update('ACCOUNT', 'totp_verified', True)
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to update the key in the configuration file")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
ok = config.update('ACCOUNT', 'enable_totp', True)
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to update the key in the configuration file")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
# Very important to also refresh the config in-memory
|
||||||
|
ok, flask.current_app.wgd_config = config.read()
|
||||||
|
if not ok:
|
||||||
|
log.error("failed to refresh the in-memory configuration")
|
||||||
|
return make_resp_obj(False, 'Internal error', {}, 500)
|
||||||
|
|
||||||
|
return make_resp_obj(totp_match)
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#!/bin/env python3
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import flask
|
||||||
|
|
||||||
|
import psutil, shutil, subprocess, time
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
|
||||||
|
class system_status:
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"CPU": self.get_cpu(),
|
||||||
|
"Memory": self.get_memory(),
|
||||||
|
"Disks": self.get_disks(),
|
||||||
|
"NetworkInterfaces": self.get_network(),
|
||||||
|
"NetworkInterfacesPriority": self.get_interface_priorities(),
|
||||||
|
"Processes": self.get_processes()
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_cpu(self):
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
"cpu_percent": psutil.cpu_percent(interval=1),
|
||||||
|
"cpu_percent_per_cpu": psutil.cpu_percent(interval=1, percpu=True)
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("CPU error %s", e)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_memory(self):
|
||||||
|
try:
|
||||||
|
v = psutil.virtual_memory()
|
||||||
|
s = psutil.swap_memory()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"VirtualMemory": {
|
||||||
|
"total": v.total,
|
||||||
|
"available": v.available,
|
||||||
|
"percent": v.percent
|
||||||
|
},
|
||||||
|
"SwapMemory": {
|
||||||
|
"total": s.total,
|
||||||
|
"available": s.free,
|
||||||
|
"percent": s.percent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("Memory error %s", e)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_disks(self):
|
||||||
|
disks = []
|
||||||
|
try:
|
||||||
|
for p in psutil.disk_partitions():
|
||||||
|
d = psutil.disk_usage(p.mountpoint)
|
||||||
|
|
||||||
|
disks.append({
|
||||||
|
"mountPoint": p.mountpoint,
|
||||||
|
"total": d.total,
|
||||||
|
"used": d.used,
|
||||||
|
"free": d.free,
|
||||||
|
"percent": d.percent
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("Disk error %s", e)
|
||||||
|
|
||||||
|
return disks
|
||||||
|
|
||||||
|
def get_network(self):
|
||||||
|
try:
|
||||||
|
first = psutil.net_io_counters(pernic=True)
|
||||||
|
time.sleep(1)
|
||||||
|
second = psutil.net_io_counters(pernic=True)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
for iface in first:
|
||||||
|
sent = (second[iface].bytes_sent - first[iface].bytes_sent) / 1024 / 1024
|
||||||
|
recv = (second[iface].bytes_recv - first[iface].bytes_recv) / 1024 / 1024
|
||||||
|
|
||||||
|
result[iface] = {
|
||||||
|
**first[iface]._asdict(),
|
||||||
|
"realtime": {
|
||||||
|
"sent": round(sent, 4),
|
||||||
|
"recv": round(recv, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("Network error %s", e)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_interface_priorities(self):
|
||||||
|
try:
|
||||||
|
if not shutil.which("ip"):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
result = subprocess.check_output(["ip", "route", "show"]).decode()
|
||||||
|
|
||||||
|
priorities = {}
|
||||||
|
|
||||||
|
for line in result.splitlines():
|
||||||
|
if "metric" in line and "dev" in line:
|
||||||
|
parts = line.split()
|
||||||
|
dev = parts[parts.index("dev") + 1]
|
||||||
|
metric = int(parts[parts.index("metric") + 1])
|
||||||
|
|
||||||
|
priorities.setdefault(dev, metric)
|
||||||
|
|
||||||
|
return priorities
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("Interface priority error %s", e)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_processes(self):
|
||||||
|
cpu_list = []
|
||||||
|
mem_list = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
for proc in psutil.process_iter():
|
||||||
|
|
||||||
|
try:
|
||||||
|
name = proc.name()
|
||||||
|
cmd = " ".join(proc.cmdline())
|
||||||
|
pid = proc.pid
|
||||||
|
|
||||||
|
cpu = proc.cpu_percent()
|
||||||
|
mem = proc.memory_percent()
|
||||||
|
|
||||||
|
cpu_list.append({
|
||||||
|
"name": name,
|
||||||
|
"command": cmd,
|
||||||
|
"pid": pid,
|
||||||
|
"percent": cpu
|
||||||
|
})
|
||||||
|
|
||||||
|
mem_list.append({
|
||||||
|
"name": name,
|
||||||
|
"command": cmd,
|
||||||
|
"pid": pid,
|
||||||
|
"percent": mem
|
||||||
|
})
|
||||||
|
|
||||||
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||||
|
continue
|
||||||
|
|
||||||
|
cpu_list.sort(key=lambda x: x["percent"], reverse=True)
|
||||||
|
mem_list.sort(key=lambda x: x["percent"], reverse=True)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"cpu_top_10": cpu_list[:20],
|
||||||
|
"memory_top_10": mem_list[:20]
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error("Process error %s", e)
|
||||||
|
return {}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
class utilities():
|
class utilities():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -19,5 +20,22 @@ class utilities():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log.critical('failed to create directory')
|
log.error('failed to create directory')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_available() -> bool:
|
||||||
|
request = urllib.request.urlopen("https://api.github.com/repos/WGDashboard/WGDashboard/releases/latest", timeout=5).read()
|
||||||
|
|
||||||
|
data = json.loads(request)
|
||||||
|
log.info(data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ProtocolsEnabled() -> list[str]:
|
||||||
|
from shutil import which
|
||||||
|
protocols = []
|
||||||
|
if which('awg') is not None and which('awg-quick') is not None:
|
||||||
|
protocols.append("awg")
|
||||||
|
if which('wg') is not None and which('wg-quick') is not None:
|
||||||
|
protocols.append("wg")
|
||||||
|
return protocols
|
||||||
@@ -5,3 +5,4 @@ sqlalchemy==2.0.48
|
|||||||
Flask==3.1.3
|
Flask==3.1.3
|
||||||
Werkzeug==3.1.6
|
Werkzeug==3.1.6
|
||||||
pyotp==2.9.0
|
pyotp==2.9.0
|
||||||
|
psutil==7.2.2
|
||||||
@@ -6,7 +6,7 @@ rm ./dist -rf
|
|||||||
|
|
||||||
echo "Compiling the new!"
|
echo "Compiling the new!"
|
||||||
|
|
||||||
cd ./admin && npm run build && cd ..
|
cd ./admin && npm install && npm run build && cd ..
|
||||||
cd ./client && npm run build && cd ..
|
cd ./client && npm install && npm run build && cd ..
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const proxy = "http://wg.local:10086/"
|
||||||
Reference in New Issue
Block a user