1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 15:20:09 +01:00

v20210402

Added more features
This commit is contained in:
Donald Cheng Hong Zou 2021-04-02 20:48:00 -04:00
parent 881c8f30ef
commit 07678300da
10 changed files with 349 additions and 132 deletions

6
.gitignore vendored
View File

@ -1,3 +1,7 @@
.vscode/sftp.json .vscode/sftp.json
src/.vscode/sftp.json src/.vscode/sftp.json
.DS_Store .DS_Store
wg.db
*.json
.idea
src/test.py

View File

@ -2,19 +2,21 @@ import os
from flask import Flask, request, render_template, redirect, url_for from flask import Flask, request, render_template, redirect, url_for
import subprocess import subprocess
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
from tinydb import TinyDB, Query import sqlite3
import time import time
import requests import requests
from operator import itemgetter
import collections
from tinydb import TinyDB, Query
conf_location = "/etc/wireguard" conf_location = "/etc/wireguard"
app = Flask("Wireguard Dashboard") app = Flask("Wireguard Dashboard")
app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['TEMPLATES_AUTO_RELOAD'] = True
css = "" css = ""
conf_data = {} conf_data = {}
def get_conf_peer_key(config_name): def get_conf_peer_key(config_name):
keys = [] keys = []
try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True) try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True)
@ -41,12 +43,31 @@ def get_conf_running_peer_number(config_name):
return running return running
def get_conf_peers_data(config_name): def get_conf_peers_data(config_name):
db = TinyDB('db/'+config_name+'.json')
peers = Query()
peer_data = {} peer_data = {}
# Get key # Get key
try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True) try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True)
except Exception: return "stopped" except Exception: return "stopped"
peer_key = peer_key.decode("UTF-8").split() peer_key = peer_key.decode("UTF-8").split()
for i in peer_key: peer_data[i] = {} for i in peer_key:
peer_data[i] = {}
if not db.search(peers.id == i):
db.insert({
"id": i,
"name": "",
"total_receive": 0,
"total_sent": 0,
"total_data": 0,
"endpoint": 0,
"status": 0,
"latest_handshake": 0,
"allowed_ip": 0,
"traffic": []
})
#Get transfer #Get transfer
try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True) try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True)
@ -57,7 +78,11 @@ def get_conf_peers_data(config_name):
download_total = 0 download_total = 0
total = 0 total = 0
for i in range(int(len(data_usage)/3)): 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) db.update({"total_receive": round(int(data_usage[count+1])/(1024**3),4),
"total_sent": round(int(data_usage[count+2])/(1024**3),4),
"total_data": round((int(data_usage[count+2])+int(data_usage[count+1]))/(1024**3),4)}, peers.id == data_usage[count])
peer_data[data_usage[count]]['total_receive'] = 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_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) peer_data[data_usage[count]]['total_data'] = round((int(data_usage[count+2])+int(data_usage[count+1]))/(1024**3),4)
count += 3 count += 3
@ -68,6 +93,8 @@ def get_conf_peers_data(config_name):
data_usage = data_usage.decode("UTF-8").split() data_usage = data_usage.decode("UTF-8").split()
count = 0 count = 0
for i in range(int(len(data_usage)/2)): for i in range(int(len(data_usage)/2)):
db.update({"endpoint": data_usage[count+1]}, peers.id == data_usage[count])
peer_data[data_usage[count]]['endpoint'] = data_usage[count+1] peer_data[data_usage[count]]['endpoint'] = data_usage[count+1]
count += 2 count += 2
@ -80,11 +107,16 @@ def get_conf_peers_data(config_name):
b = timedelta(minutes=2) b = timedelta(minutes=2)
for i in range(int(len(data_usage)/2)): for i in range(int(len(data_usage)/2)):
minus = now - datetime.fromtimestamp(int(data_usage[count+1])) minus = now - datetime.fromtimestamp(int(data_usage[count+1]))
status = ""
if minus < b: if minus < b:
peer_data[data_usage[count]]['status'] = "running" peer_data[data_usage[count]]['status'] = "running"
status = "running"
else: else:
peer_data[data_usage[count]]['status'] = "stopped" peer_data[data_usage[count]]['status'] = "stopped"
peer_data[data_usage[count]]['latest_handshake'] = minus status = "stopped"
db.update({"latest_handshake": str(minus).split(".")[0], "status": status}, peers.id == data_usage[count])
peer_data[data_usage[count]]['latest_handshake'] = str(minus).split(".")[0]
count += 2 count += 2
#Get allowed ip #Get allowed ip
@ -93,27 +125,30 @@ def get_conf_peers_data(config_name):
data_usage = data_usage.decode("UTF-8").split() data_usage = data_usage.decode("UTF-8").split()
count = 0 count = 0
for i in range(int(len(data_usage)/2)): for i in range(int(len(data_usage)/2)):
db.update({"allowed_ip": data_usage[count+1]}, peers.id == data_usage[count])
peer_data[data_usage[count]]['allowed_ip'] = data_usage[count+1] peer_data[data_usage[count]]['allowed_ip'] = data_usage[count+1]
count += 2 count += 2
return peer_data result = db.all()
result = sorted(result, key=lambda d: d['status'])
return result
def get_conf_pub_key(config_name): def get_conf_pub_key(config_name):
try: pub_key = subprocess.check_output("wg show "+config_name+" public-key", shell=True) try: pub_key = subprocess.check_output("wg show "+config_name+" public-key", shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped" except Exception: return "stopped"
return pub_key.decode("UTF-8") return pub_key.decode("UTF-8")
def get_conf_listen_port(config_name): def get_conf_listen_port(config_name):
try: pub_key = subprocess.check_output("wg show "+config_name+" listen-port", shell=True) try: pub_key = subprocess.check_output("wg show "+config_name+" listen-port", shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped" except Exception: return "stopped"
return pub_key.decode("UTF-8") return pub_key.decode("UTF-8")
def get_conf_total_data(config_name): def get_conf_total_data(config_name):
try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True) try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped" except Exception: return "stopped"
data_usage = data_usage.decode("UTF-8").split() data_usage = data_usage.decode("UTF-8").split()
count = 0 count = 0
@ -133,7 +168,7 @@ def get_conf_total_data(config_name):
def get_conf_status(config_name): def get_conf_status(config_name):
try: status = subprocess.check_output("wg show "+config_name, shell=True) try: status = subprocess.check_output("wg show "+config_name, shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped" except Exception: return "stopped"
else: return "running" else: return "running"
@ -148,6 +183,7 @@ def get_conf_list():
temp['checked'] = 'checked' temp['checked'] = 'checked'
else: temp['checked'] = "" else: temp['checked'] = ""
conf.append(temp) conf.append(temp)
conf = sorted(conf, key=itemgetter('status'))
return conf return conf
@app.route('/',methods=['GET']) @app.route('/',methods=['GET'])
@ -157,6 +193,21 @@ def index():
@app.route('/configuration/<config_name>', methods=['GET']) @app.route('/configuration/<config_name>', methods=['GET'])
def conf(config_name): def conf(config_name):
conf_data = {
"name": config_name,
"status": get_conf_status(config_name),
"checked": ""
}
if conf_data['status'] == "stopped":
return redirect('/')
else:
conf_data['checked'] = "checked"
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data)
@app.route('/get_config/<config_name>', methods=['GET'])
def get_conf(config_name):
db = TinyDB('db/'+config_name+'.json')
conf_data = { conf_data = {
"name": config_name, "name": config_name,
"status": get_conf_status(config_name), "status": get_conf_status(config_name),
@ -165,14 +216,12 @@ def conf(config_name):
"listen_port": get_conf_listen_port(config_name), "listen_port": get_conf_listen_port(config_name),
"peer_data":get_conf_peers_data(config_name), "peer_data":get_conf_peers_data(config_name),
"running_peer": get_conf_running_peer_number(config_name), "running_peer": get_conf_running_peer_number(config_name),
"checked": ""
} }
if conf_data['status'] == "stopped": if conf_data['status'] == "stopped":
print(conf_data)
return redirect('/') return redirect('/')
else: else:
conf_data['checked'] = "checked" conf_data['checked'] = "checked"
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data) return render_template('get_conf.html', conf=get_conf_list(), conf_data=conf_data)
@app.route('/switch/<config_name>', methods=['GET']) @app.route('/switch/<config_name>', methods=['GET'])
@ -208,6 +257,8 @@ def add_peer(config_name):
@app.route('/remove_peer/<config_name>', methods=['POST']) @app.route('/remove_peer/<config_name>', methods=['POST'])
def remove_peer(config_name): def remove_peer(config_name):
db = TinyDB("db/"+config_name+".json")
peers = Query()
data = request.get_json() data = request.get_json()
delete_key = data['peer_id'] delete_key = data['peer_id']
keys = get_conf_peer_key(config_name) keys = get_conf_peer_key(config_name)
@ -217,8 +268,35 @@ def remove_peer(config_name):
try: try:
status = subprocess.check_output("wg set "+config_name+" peer "+delete_key+" remove", shell=True, stderr=subprocess.STDOUT) status = subprocess.check_output("wg set "+config_name+" peer "+delete_key+" remove", shell=True, stderr=subprocess.STDOUT)
status = subprocess.check_output("wg-quick save "+config_name, shell=True, stderr=subprocess.STDOUT) status = subprocess.check_output("wg-quick save "+config_name, shell=True, stderr=subprocess.STDOUT)
db.remove(peers.id == delete_key)
return "true" return "true"
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
return exc.output.strip() return exc.output.strip()
@app.route('/save_peer_name/<config_name>', methods=['POST'])
def save_peer_name(config_name):
data = request.get_json()
id = data['id']
name = data['name']
db = TinyDB("db/"+config_name+".json")
peers = Query()
db.update({"name": name}, peers.id == id)
return id + " " + name
@app.route('/get_peer_name/<config_name>', methods=['POST'])
def get_peer_name(config_name):
data = request.get_json()
id = data['id']
db = TinyDB("db/"+config_name+".json")
peers = Query()
result = db.search(peers.id == id)
return result[0]['name']
# db.update({"name": name}, peers.id == id)
app.run(host='0.0.0.0',debug=False, port=10086) app.run(host='0.0.0.0',debug=False, port=10086)

1
src/db/hi.txt Normal file
View File

@ -0,0 +1 @@
You can delete this later ;)

1
src/static/bootstrap4-toggle.min.js vendored Normal file
View File

@ -0,0 +1 @@
!function(a){"use strict";function l(t,e){this.$element=a(t),this.options=a.extend({},this.defaults(),e),this.render()}l.VERSION="3.6.0",l.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"light",size:"normal",style:"",width:null,height:null},l.prototype.defaults=function(){return{on:this.$element.attr("data-on")||l.DEFAULTS.on,off:this.$element.attr("data-off")||l.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||l.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||l.DEFAULTS.offstyle,size:this.$element.attr("data-size")||l.DEFAULTS.size,style:this.$element.attr("data-style")||l.DEFAULTS.style,width:this.$element.attr("data-width")||l.DEFAULTS.width,height:this.$element.attr("data-height")||l.DEFAULTS.height}},l.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var t="large"===this.options.size||"lg"===this.options.size?"btn-lg":"small"===this.options.size||"sm"===this.options.size?"btn-sm":"mini"===this.options.size||"xs"===this.options.size?"btn-xs":"",e=a('<label for="'+this.$element.prop("id")+'" class="btn">').html(this.options.on).addClass(this._onstyle+" "+t),s=a('<label for="'+this.$element.prop("id")+'" class="btn">').html(this.options.off).addClass(this._offstyle+" "+t),o=a('<span class="toggle-handle btn btn-light">').addClass(t),i=a('<div class="toggle-group">').append(e,s,o),l=a('<div class="toggle btn" data-toggle="toggle" role="button">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(t).addClass(this.options.style);this.$element.wrap(l),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:e,$toggleOff:s,$toggleGroup:i}),this.$toggle.append(i);var n=this.options.width||Math.max(e.outerWidth(),s.outerWidth())+o.outerWidth()/2,h=this.options.height||Math.max(e.outerHeight(),s.outerHeight());e.addClass("toggle-on"),s.addClass("toggle-off"),this.$toggle.css({width:n,height:h}),this.options.height&&(e.css("line-height",e.height()+"px"),s.css("line-height",s.height()+"px")),this.update(!0),this.trigger(!0)},l.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},l.prototype.on=function(t){if(this.$element.prop("disabled"))return!1;this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),t||this.trigger()},l.prototype.off=function(t){if(this.$element.prop("disabled"))return!1;this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),t||this.trigger()},l.prototype.enable=function(){this.$toggle.removeClass("disabled"),this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},l.prototype.disable=function(){this.$toggle.addClass("disabled"),this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},l.prototype.update=function(t){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(t):this.off(t)},l.prototype.trigger=function(t){this.$element.off("change.bs.toggle"),t||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},l.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var t=a.fn.bootstrapToggle;a.fn.bootstrapToggle=function(o){var i=Array.prototype.slice.call(arguments,1)[0];return this.each(function(){var t=a(this),e=t.data("bs.toggle"),s="object"==typeof o&&o;e||t.data("bs.toggle",e=new l(this,s)),"string"==typeof o&&e[o]&&"boolean"==typeof i?e[o](i):"string"==typeof o&&e[o]&&e[o]()})},a.fn.bootstrapToggle.Constructor=l,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=t,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(t){a(this).find("input[type=checkbox]").bootstrapToggle("toggle"),t.preventDefault()})}(jQuery);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -121,4 +121,22 @@ body {
.info h6{ .info h6{
line-break: anywhere; line-break: anywhere;
}
.btn-control{
border: none !important;
padding: 0;
padding-right: 0.5rem;
}
.btn-control:hover{
background: white;
}
.btn-delete-peer:hover{
color: #dc3545;
}
.btn-setting-peer:hover{
color:#007bff
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -8,11 +8,12 @@
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='dashboard.css') }}"> <link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='dashboard.css') }}">
<link href="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css">
</head> </head>
<body> <body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow"> <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
<a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">Wireguard Dashboard</a> <a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="/">Wireguard Dashboard</a>
<button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse" <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse"
data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation"> data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@ -38,109 +39,9 @@
</nav> </nav>
</div> </div>
</div> </div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4"> <div id="config_body">
<div class="info mt-4">
<div class="row"> </div>
<div class="col-sm">
<small class="text-muted"><strong>CONFIGURATION</strong></small>
<h1 class="mb-3">{{conf_data['name']}}</h1>
</div>
<div class="col-sm">
<small class="text-muted"><strong>ACTION</strong></small><br>
<input class="mt-2 switch" id="{{conf_data['name']}}" type="checkbox" data-toggle="toggle" {{conf_data['checked']}} data-size="sm">
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['status']}}<span class="dot dot-{{conf_data['status']}}"></span></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>CONNECTED PEERS</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['running_peer']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL DATA USAGE</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][0]}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL RECIEVED</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][1]}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL SENT</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][2]}} GB</h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>PUBLIC KEY</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{conf_data['public_key']}}</samp></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>LISTEN PORT</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{conf_data['listen_port']}}</samp></h6>
</div>
</div>
<hr>
<div class="button-div" style="text-align: right;">
<button type="button" class="btn btn-outline-primary btn-sm mb-3" data-toggle="modal" data-target="#add_modal">
<strong>ADD PEER</strong>
</button>
</div>
</div>
{% for i in conf_data['peer_data']%}
<div class="card mb-3">
<div class="card-body">
<div class="row">
<div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['status']}}<span class="dot dot-{{conf_data['peer_data'][i]['status']}}"></span></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>PEER</strong></small>
<h6><samp>{{i}}</samp></h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>ALLOWED IP</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['allowed_ip']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>LATEST HANDSHAKE</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['latest_handshake']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>END POINT</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['endpoint']}}</h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL DATA USAGE</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['total_data']}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL RECIEVED</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['total_recive']}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL SENT</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['total_sent']}} GB</h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<!-- <small class="text-muted"><strong>ACTION</strong></small> -->
<div class="button-group">
<button type="button" class="btn btn-outline-danger btn-sm btn-delete-peer" id="{{i}}" data-toggle="modal" data-target="#delete_modal"><span class="material-icons">delete_forever</span></button>
</div>
</div>
</div>
</div>
</div>
{%endfor%}
</main>
</div> </div>
<div class="modal fade" id="add_modal" data-backdrop="static" data-keyboard="false" tabindex="-1" <div class="modal fade" id="add_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true"> aria-labelledby="staticBackdropLabel" aria-hidden="true">
@ -201,6 +102,44 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="setting_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true" conf_id={{conf_data['name']}} peer_id="">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="peer_name"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="peer_name" class="form-label">Name</label>
<input type="text" class="form-control" id="peer_name_textbox" placeholder="">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="save_peer_name" conf_id={{conf_data['name']}} peer_id="">Save</button>
</div>
</div>
</div>
</div>
<div class="position-fixed top-0 right-0 p-3" style="z-index: 5; right: 0; top: 50px;">
<div id="alertToast" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
<div class="toast-header">
<strong class="mr-auto">Wireguard Dashboard</strong>
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body">
</div>
</div>
</div>
</body> </body>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
@ -209,7 +148,32 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"
integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script> <script>
function load_data(){
$.ajax({
method: "GET",
url: "/get_config/"+"{{conf_data['name']}}",
headers:{
"Content-Type": "application/json"
},
async:false,
success: function (response){
$("#config_body").html(response);
$.ajax({
url: "{{ url_for('static',filename='bootstrap4-toggle.min.js') }}",
dataType: "script",
cache: true
});
}
})
}
$(document).ready(function(){
load_data();
setInterval(function(){
load_data();
}, 10000)
});
</script>
<script> <script>
$('.switch').change(function() { $('.switch').change(function() {
if ($(this).prop('checked') == false){ if ($(this).prop('checked') == false){
@ -221,7 +185,6 @@
location.replace("/switch/"+$(this).attr('id')); location.replace("/switch/"+$(this).attr('id'));
} }
}); });
$("#save_peer").click(function(){ $("#save_peer").click(function(){
if ($("#allowed_ips") != "" && $("#public_key") != ""){ if ($("#allowed_ips") != "" && $("#public_key") != ""){
var conf = $(this).attr('conf_id') var conf = $(this).attr('conf_id')
@ -246,9 +209,13 @@
} }
}) })
$(".btn-delete-peer").click(function(){ $("body").on("click", ".btn-delete-peer", function(){
var peer_id = $(this).attr("id"); var peer_id = $(this).attr("id");
$("#delete_peer").attr("peer_id", peer_id); $("#delete_peer").attr("peer_id", peer_id);
})
$(".btn-delete-peer").click(function(){
}); });
$("#delete_peer").click(function(){ $("#delete_peer").click(function(){
@ -275,8 +242,48 @@
// setInterval(function(){ var myModal = new bootstrap.Modal(document.getElementById('setting_modal'), {
// location.reload(); keyboard: false
// }, 10000) })
$("body").on("click", ".btn-setting-peer", function(){
myModal.toggle();
var peer_id = $(this).attr("id");
$("#save_peer_name").attr("peer_id", peer_id);
$.ajax({
method: "POST",
url: "/get_peer_name/"+$("#setting_modal").attr("conf_id"),
headers:{
"Content-Type": "application/json"
},
data: JSON.stringify({"id": peer_id}),
success: function(response){
if (response == ""){
$("#setting_modal .peer_name").html("Untitled Peer");
}else{
$("#setting_modal .peer_name").html(response);
$("#peer_name_textbox").val(response)
}
}
})
});
$("#save_peer_name").click(function (){
var peer_id = $(this).attr("peer_id");
$.ajax({
method: "POST",
url: "/save_peer_name/"+"{{conf_data['name']}}",
headers:{
"Content-Type": "application/json"
},
data: JSON.stringify({id: peer_id, name: $("#peer_name_textbox").val()}),
success: function (response){
myModal.toggle();
load_data();
$('#alertToast').toast('show');
$('#alertToast .toast-body').html("Name Saved!");
}
})
})
</script> </script>
</html> </html>

112
src/templates/get_conf.html Normal file
View File

@ -0,0 +1,112 @@
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4">
<div class="info mt-4">
<div class="row">
<div class="col-sm">
<small class="text-muted"><strong>CONFIGURATION</strong></small>
<h1 class="mb-3">{{conf_data['name']}}</h1>
</div>
<div class="col-sm">
<small class="text-muted"><strong>ACTION</strong></small><br>
<input class="mt-2 switch" id="{{conf_data['name']}}" type="checkbox" data-toggle="toggle" {{conf_data['checked']}} data-size="sm">
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['status']}}<span class="dot dot-{{conf_data['status']}}"></span></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>CONNECTED PEERS</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['running_peer']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL DATA USAGE</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][0]}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL RECIEVED</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][1]}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL SENT</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['total_data_usage'][2]}} GB</h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>PUBLIC KEY</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{conf_data['public_key']}}</samp></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>LISTEN PORT</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{conf_data['listen_port']}}</samp></h6>
</div>
</div>
<hr>
<div class="button-div" style="text-align: right;">
<button type="button" class="btn btn-outline-primary btn-sm mb-3" data-toggle="modal" data-target="#add_modal">
<strong>ADD PEER</strong>
</button>
</div>
</div>
{% for i in conf_data['peer_data']%}
<div class="card mb-3">
<div class="card-header">
{% if not i['name']%}
{{ "Untitled Peer" }}
{% else %}
{{i['name']}}
{% endif %}
</div>
<div class="card-body">
<div class="row">
<div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;">{{i['status']}}<span class="dot dot-{{i['status']}}"></span></h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>PEER</strong></small>
<h6><samp>{{i['id']}}</samp></h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>ALLOWED IP</strong></small>
<h6 style="text-transform: uppercase;">{{i['allowed_ip']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>LATEST HANDSHAKE</strong></small>
<h6 style="text-transform: uppercase;">{{i['latest_handshake']}}</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>END POINT</strong></small>
<h6 style="text-transform: uppercase;">{{i['endpoint']}}</h6>
</div>
<div class="w-100"></div>
{# <div class="col-sm">#}
{# <small class="text-muted"><strong>TOTAL DATA USAGE</strong></small>#}
{# <h6 style="text-transform: uppercase;">{{i['total_data']}} GB</h6>#}
{# </div>#}
<div class="col-sm">
<small class="text-muted"><strong>TOTAL RECEIVED</strong></small>
<h6 style="text-transform: uppercase;"><i class="bi bi-arrow-down-right"></i> {{i['total_receive']}} GB</h6>
</div>
<div class="col-sm">
<small class="text-muted"><strong>TOTAL SENT</strong></small>
<h6 style="text-transform: uppercase;"><i class="bi bi-arrow-up-right"></i> {{i['total_sent']}} GB</h6>
</div>
<div class="w-100"></div>
<div class="col-sm">
<!-- <small class="text-muted"><strong>ACTION</strong></small> -->
<div class="button-group">
<hr>
<button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" id="{{i['id']}}" data-toggle="modal"><i class="bi bi-gear-fill"></i></button>
<button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="{{i['id']}}" data-toggle="modal" data-target="#delete_modal"><i class="bi bi-x-circle-fill"></i></button>
</div>
</div>
</div>
</div>
</div>
{%endfor%}
</main>

View File

@ -1,4 +0,0 @@
from tinydb import TinyDB, Query
conf_db = TinyDB("json/conf.json")
print(conf_db.all())