diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..a580bdf Binary files /dev/null and b/.DS_Store differ diff --git a/dashboard.py b/dashboard.py new file mode 100644 index 0000000..d2b31fd --- /dev/null +++ b/dashboard.py @@ -0,0 +1,137 @@ +import os +from flask import Flask, request, render_template +from tinydb import TinyDB, Query +import subprocess +from datetime import datetime + +conf_location = "/etc/wireguard" + +app = Flask("Wireguard Dashboard") +app.config['TEMPLATES_AUTO_RELOAD'] = True +# app.config['STATIC_AUTO_RELOAD'] = True +css = "" + +def get_conf_peers_data(config_name): + peer_data = {} + # Get key + try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True) + except Exception: return "stopped" + peer_key = peer_key.decode("UTF-8").split() + for i in peer_key: peer_data[i] = {} + + #Get transfer + try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True) + except Exception: return "stopped" + data_usage = data_usage.decode("UTF-8").split() + count = 0 + upload_total = 0 + download_total = 0 + total = 0 + for i in range(int(len(data_usage)/3)): + peer_data[data_usage[count]]['total_recive'] = round(int(data_usage[count+1])/(1024**3), 4) + peer_data[data_usage[count]]['total_sent'] = round(int(data_usage[count+2])/(1024**3),4) + peer_data[data_usage[count]]['total_data'] = round((int(data_usage[count+2])+int(data_usage[count+1]))/(1024**3),4) + count += 3 + + #Get endpoint + try: data_usage = subprocess.check_output("wg show "+config_name+" endpoints", shell=True) + except Exception: return "stopped" + data_usage = data_usage.decode("UTF-8").split() + count = 0 + for i in range(int(len(data_usage)/2)): + peer_data[data_usage[count]]['endpoint'] = data_usage[count+1] + count += 2 + + #Get latest handshakes + try: data_usage = subprocess.check_output("wg show "+config_name+" latest-handshakes", shell=True) + except Exception: return "stopped" + data_usage = data_usage.decode("UTF-8").split() + count = 0 + now = datetime.now() + + for i in range(int(len(data_usage)/2)): + minus = now - datetime.fromtimestamp(int(data_usage[count+1])) + peer_data[data_usage[count]]['latest_handshake'] = minus + count += 2 + + #Get allowed ip + try: data_usage = subprocess.check_output("wg show "+config_name+" allowed-ips", shell=True) + except Exception: return "stopped" + data_usage = data_usage.decode("UTF-8").split() + count = 0 + for i in range(int(len(data_usage)/2)): + peer_data[data_usage[count]]['allowed_ip'] = data_usage[count+1] + count += 2 + + return peer_data + + + + +def get_conf_pub_key(config_name): + try: pub_key = subprocess.check_output("wg show "+config_name+" public-key", shell=True) + except Exception: return "stopped" + return pub_key.decode("UTF-8") + +def get_conf_listen_port(config_name): + try: pub_key = subprocess.check_output("wg show "+config_name+" listen-port", shell=True) + except Exception: return "stopped" + return pub_key.decode("UTF-8") + + + +def get_conf_total_data(config_name): + try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True) + except Exception: return "stopped" + data_usage = data_usage.decode("UTF-8").split() + count = 0 + upload_total = 0 + download_total = 0 + total = 0 + for i in range(int(len(data_usage)/3)): + upload_total += int(data_usage[count+1]) + download_total += int(data_usage[count+2]) + count += 3 + + total = round(((((upload_total+download_total)/1024)/1024)/1024),3) + upload_total = round(((((upload_total)/1024)/1024)/1024),3) + download_total = round(((((download_total)/1024)/1024)/1024),3) + + return [total, upload_total, download_total] + + +def get_conf_status(config_name): + try: status = subprocess.check_output("wg show "+config_name, shell=True) + except Exception: return "stopped" + else: return "running" + + +def get_conf_list(): + conf = [] + for i in os.listdir(conf_location): + if ".conf" in i: + i = i.replace('.conf','') + temp = {"conf":i, "status":get_conf_status(i)} + conf.append(temp) + return conf + +@app.route('/',methods=['GET']) +def index(): + return render_template('index.html', conf=get_conf_list()) + + +@app.route('/configuration/', methods=['GET']) +def conf(config_name): + + conf_data = { + "name": config_name, + "status": get_conf_status(config_name), + "total_data_usage": get_conf_total_data(config_name), + "public_key": get_conf_pub_key(config_name), + "listen_port": get_conf_listen_port(config_name), + "peer_data":get_conf_peers_data(config_name) + } + return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data) + + +app.run(host='0.0.0.0',debug=False, port=10086) diff --git a/static/dashboard.css b/static/dashboard.css new file mode 100644 index 0000000..895ad7a --- /dev/null +++ b/static/dashboard.css @@ -0,0 +1,124 @@ +body { + font-size: .875rem; +} + +.feather { + width: 16px; + height: 16px; + vertical-align: text-bottom; +} + +/* + * Sidebar + */ + +.sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + z-index: 100; /* Behind the navbar */ + padding: 48px 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); +} + +@media (max-width: 767.98px) { + .sidebar { + top: 5rem; + } +} + +.sidebar-sticky { + position: relative; + top: 0; + height: calc(100vh - 48px); + padding-top: .5rem; + overflow-x: hidden; + overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ +} + +@supports ((position: -webkit-sticky) or (position: sticky)) { + .sidebar-sticky { + position: -webkit-sticky; + position: sticky; + } +} + +.sidebar .nav-link { + font-weight: 500; + color: #333; +} + +.sidebar .nav-link .feather { + margin-right: 4px; + color: #999; +} + +.sidebar .nav-link.active { + color: #007bff; +} + +.sidebar .nav-link:hover .feather, +.sidebar .nav-link.active .feather { + color: inherit; +} + +.sidebar-heading { + font-size: .75rem; + text-transform: uppercase; +} + +/* + * Navbar + */ + +.navbar-brand { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: 1rem; + background-color: rgba(0, 0, 0, .25); + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); +} + +.navbar .navbar-toggler { + top: .25rem; + right: 1rem; +} + +.navbar .form-control { + padding: .75rem 1rem; + border-width: 0; + border-radius: 0; +} + +.form-control-dark { + color: #fff; + background-color: rgba(255, 255, 255, .1); + border-color: rgba(255, 255, 255, .1); +} + +.form-control-dark:focus { + border-color: transparent; + box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); +} + +.dot{ + width: 10px; + height: 10px; + border-radius: 50px; + display: inline-block; + margin-left: 10px; +} + +.dot-running{ + background-color: #28a745!important; +} + +.dot-stopped{ + background-color: #6c757d!important; +} + + +.info h6{ + line-break: anywhere; +} \ No newline at end of file diff --git a/templates/configuration.html b/templates/configuration.html new file mode 100644 index 0000000..94cd97b --- /dev/null +++ b/templates/configuration.html @@ -0,0 +1,130 @@ + + + + + + Wireguard Dashboard + + + + + + +
+
+
+ +
+
+
+
+ CONFIGURATION +

{{conf_data['name']}}

+
+
+ STATUS +
{{conf_data['status']}}
+
+
+ TOTAL DATA USAGE +
{{conf_data['total_data_usage'][0]}} GB
+
+
+ TOTAL RECIEVED +
{{conf_data['total_data_usage'][1]}} GB
+
+
+ TOTAL SENT +
{{conf_data['total_data_usage'][2]}} GB
+
+
+
+ PUBLIC KEY +
{{conf_data['public_key']}}
+
+
+ LISTEN PORT +
{{conf_data['listen_port']}}
+
+
+
+
+ {% for i in conf_data['peer_data']%} +
+
+
+
+ ALLOWED IP +
{{conf_data['peer_data'][i]['allowed_ip']}}
+
+
+ LATEST HANDSHAKE +
{{conf_data['peer_data'][i]['latest_handshake']}}
+
+
+
+ PEER +
{{i}}
+
+
+ END POINT +
{{conf_data['peer_data'][i]['endpoint']}}
+
+
+
+ TOTAL DATA USAGE +
{{conf_data['peer_data'][i]['total_data']}} GB
+
+
+ TOTAL RECIEVED +
{{conf_data['peer_data'][i]['total_recive']}} GB
+
+
+ TOTAL SENT +
{{conf_data['peer_data'][i]['total_sent']}} GB
+
+
+
+
+ {%endfor%} + +
+
+ + + + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..9bde758 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,71 @@ + + + + + + Wireguard Dashboard + + + + + + +
+
+
+ +
+
+
+ {% for i in conf%} +
+
+ +
{{i['conf']}}
+
+
Status: {{i['status']}} + +
+
+
+ {%endfor%} +
+
+ + + + + + \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..bbca88c --- /dev/null +++ b/test.py @@ -0,0 +1,5 @@ +import os +import subprocess +try: status = subprocess.check_output("wg show wg0", shell=True) +except Exception: print("false") +else:print(status.decode("UTF-8")) \ No newline at end of file