1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 15:20:09 +01:00
This commit is contained in:
Donald Cheng Hong Zou 2021-04-03 14:06:21 -04:00
parent 7e770b9b5d
commit 0c3960d8d9
3 changed files with 247 additions and 122 deletions

View File

@ -4,16 +4,21 @@ import subprocess
from datetime import datetime, date, time, timedelta
from operator import itemgetter
from tinydb import TinyDB, Query
import threading
conf_location = "/etc/wireguard"
app = Flask("Wireguard Dashboard")
app.config['TEMPLATES_AUTO_RELOAD'] = True
css = ""
conf_data = {}
def get_conf_peer_key(config_name):
keys = []
try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True)
except Exception: return "stopped"
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: keys.append(i)
return keys
@ -21,28 +26,68 @@ def get_conf_peer_key(config_name):
def get_conf_running_peer_number(config_name):
running = 0
#Get latest handshakes
try: data_usage = subprocess.check_output("wg show "+config_name+" latest-handshakes", shell=True)
except Exception: return "stopped"
# 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()
b = timedelta(minutes=2)
for i in range(int(len(data_usage)/2)):
minus = now - datetime.fromtimestamp(int(data_usage[count+1]))
for i in range(int(len(data_usage) / 2)):
minus = now - datetime.fromtimestamp(int(data_usage[count + 1]))
if minus < b:
running += 1
count += 2
return running
def get_conf_peers_data(config_name):
db = TinyDB('db/'+config_name+'.json')
db = TinyDB('db/' + config_name + '.json')
peers = Query()
peer_data = {}
# Read Configuration File Start
conf_location = "/etc/wireguard/wg0.conf"
f = open(conf_location, 'r')
file = f.read().split("\n")
conf_peer_data = {
"Interface": {},
"Peers": []
}
interface = []
peers_start = 0
for i in range(len(file)):
if file[i] == "[Peer]":
peers_start = i
break
else:
if len(file[i]) > 0:
if file[i] != "[Interface]":
tmp = file[i].replace(" ", "").split("=", 1)
conf_peer_data['Interface'][tmp[0]] = tmp[1]
conf_peers = file[peers_start:]
peer = -1
for i in conf_peers:
if i == "[Peer]":
peer += 1
conf_peer_data["Peers"].append({})
else:
if len(i) > 0:
tmp = i.replace(" ", "").split("=", 1)
if len(tmp) == 2:
conf_peer_data["Peers"][peer][tmp[0]] = tmp[1]
# Read Configuration File End
# Get key
try: peer_key = subprocess.check_output("wg show "+config_name+" peers", shell=True)
except Exception: return "stopped"
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()
now = datetime.now()
current_time = now.strftime("%Y-%m-%d %H:%M:%S")
for i in peer_key:
peer_data[i] = {}
if not db.search(peers.id == i):
@ -59,47 +104,51 @@ def get_conf_peers_data(config_name):
"traffic": []
})
#Get transfer
try: data_usage = subprocess.check_output("wg show "+config_name+" transfer", shell=True)
except Exception: return "stopped"
# 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)):
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_data'] = round((int(data_usage[count+2])+int(data_usage[count+1]))/(1024**3),4)
for i in range(int(len(data_usage) / 3)):
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_data'] = round(
(int(data_usage[count + 2]) + int(data_usage[count + 1])) / (1024 ** 3), 4)
traffic = db.search(peers.id == data_usage[count])[0]['traffic']
traffic.append({"time": current_time, "total_receive": round(int(data_usage[count + 1]) / (1024 ** 3), 4),
"total_sent": round(int(data_usage[count + 2]) / (1024 ** 3), 4)})
db.update({"traffic": traffic}, peers.id == data_usage[count])
count += 3
#Get endpoint
try: data_usage = subprocess.check_output("wg show "+config_name+" endpoints", shell=True)
except Exception: return "stopped"
# 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)):
db.update({"endpoint": data_usage[count+1]}, peers.id == data_usage[count])
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
#Get latest handshakes
try: data_usage = subprocess.check_output("wg show "+config_name+" latest-handshakes", shell=True)
except Exception: return "stopped"
# 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()
b = timedelta(minutes=2)
for i in range(int(len(data_usage)/2)):
minus = now - datetime.fromtimestamp(int(data_usage[count+1]))
for i in range(int(len(data_usage) / 2)):
minus = now - datetime.fromtimestamp(int(data_usage[count + 1]))
status = ""
if minus < b:
peer_data[data_usage[count]]['status'] = "running"
@ -111,75 +160,96 @@ def get_conf_peers_data(config_name):
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
#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)):
db.update({"allowed_ip": data_usage[count+1]}, peers.id == data_usage[count])
peer_data[data_usage[count]]['allowed_ip'] = data_usage[count+1]
count += 2
# Get allowed ip
for i in conf_peer_data["Peers"]:
db.update({"allowed_ip":i['AllowedIPs']}, peers.id == i["PublicKey"])
def getdb(config_name):
get_conf_peers_data(config_name)
db = TinyDB('db/' + config_name + '.json')
result = db.all()
result = sorted(result, key=lambda d: d['status'])
return result
def get_conf_pub_key(config_name):
try: pub_key = subprocess.check_output("wg show "+config_name+" public-key", shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped"
try:
pub_key = subprocess.check_output("wg show " + config_name + " public-key", shell=True,
stderr=subprocess.STDOUT)
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, stderr=subprocess.STDOUT)
except Exception: return "stopped"
try:
pub_key = subprocess.check_output("wg show " + config_name + " listen-port", shell=True,
stderr=subprocess.STDOUT)
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, stderr=subprocess.STDOUT)
except Exception: return "stopped"
try:
data_usage = subprocess.check_output("wg show " + config_name + " transfer", shell=True,
stderr=subprocess.STDOUT)
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])
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),4)
upload_total = round(((((upload_total)/1024)/1024)/1024),4)
download_total = round(((((download_total)/1024)/1024)/1024),4)
total = round(((((upload_total + download_total) / 1024) / 1024) / 1024), 4)
upload_total = round(((((upload_total) / 1024) / 1024) / 1024), 4)
download_total = round(((((download_total) / 1024) / 1024) / 1024), 4)
return [total, upload_total, download_total]
def get_conf_status(config_name):
try: status = subprocess.check_output("wg show "+config_name, shell=True, stderr=subprocess.STDOUT)
except Exception: return "stopped"
else: return "running"
try:
status = subprocess.check_output("wg show " + config_name, shell=True, stderr=subprocess.STDOUT)
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), "public_key": get_conf_pub_key(i)}
i = i.replace('.conf', '')
temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)}
if temp['status'] == "running":
temp['checked'] = 'checked'
else: temp['checked'] = ""
else:
temp['checked'] = ""
conf.append(temp)
conf = sorted(conf, key=itemgetter('status'))
return conf
@app.route('/',methods=['GET'])
def get_running_conf_list():
conf = []
for i in os.listdir(conf_location):
if ".conf" in i:
i = i.replace('.conf', '')
if get_conf_status(i) == "running":
conf.append(i)
return conf
@app.route('/', methods=['GET'])
def index():
return render_template('index.html', conf=get_conf_list())
@ -197,9 +267,10 @@ def conf(config_name):
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')
db = TinyDB('db/' + config_name + '.json')
conf_data = {
"name": config_name,
@ -207,7 +278,7 @@ def get_conf(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),
"peer_data": getdb(config_name),
"running_peer": get_conf_running_peer_number(config_name),
}
if conf_data['status'] == "stopped":
@ -221,11 +292,15 @@ def get_conf(config_name):
def switch(config_name):
status = get_conf_status(config_name)
if status == "running":
try: status = subprocess.check_output("wg-quick down "+config_name, shell=True)
except Exception: return redirect('/')
try:
status = subprocess.check_output("wg-quick down " + config_name, shell=True)
except Exception:
return redirect('/')
elif status == "stopped":
try: status = subprocess.check_output("wg-quick up "+config_name, shell=True)
except Exception: return redirect('/')
try:
status = subprocess.check_output("wg-quick up " + config_name, shell=True)
except Exception:
return redirect('/')
return redirect('/')
@ -239,18 +314,21 @@ def add_peer(config_name):
return "Key already exist."
else:
status = ""
try:
status = subprocess.check_output("wg set "+config_name+" peer "+public_key+" allowed-ips "+allowed_ips, shell=True, stderr=subprocess.STDOUT)
status = subprocess.check_output("wg-quick save "+config_name, shell=True, stderr=subprocess.STDOUT)
try:
status = subprocess.check_output(
"wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True,
stderr=subprocess.STDOUT)
status = subprocess.check_output("wg-quick save " + config_name, shell=True, stderr=subprocess.STDOUT)
return "true"
except subprocess.CalledProcessError as exc:
return exc.output.strip()
# return redirect('/configuration/'+config_name)
@app.route('/remove_peer/<config_name>', methods=['POST'])
def remove_peer(config_name):
db = TinyDB("db/"+config_name+".json")
db = TinyDB("db/" + config_name + ".json")
peers = Query()
data = request.get_json()
delete_key = data['peer_id']
@ -259,37 +337,39 @@ def remove_peer(config_name):
return "This key does not exist"
else:
try:
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 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)
db.remove(peers.id == delete_key)
return "true"
except subprocess.CalledProcessError as exc:
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")
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")
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)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=False, port=10086)
# for i in get_running_conf_list():
# p = Process(target=get_conf_peers_data, args=(i,))
# p.start()

View File

@ -9,6 +9,7 @@
<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 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.1/dist/chart.min.js"></script>
</head>
<body>
@ -171,7 +172,7 @@
load_data();
setInterval(function(){
load_data();
}, 10000)
}, 15000)
});
</script>
<script>

View File

@ -52,29 +52,42 @@
{% 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 class="row">
<div class="col">
<div class="card-header-body ">
{% if not i['name']%}
{{ "Untitled Peer" }}
{% else %}
{{i['name']}}
{% endif %}
<span class="dot dot-{{i['status']}}"></span>
</div>
</div>
<div class="col" style="text-align: right">
<p class="text-primary" style="text-transform: uppercase; display: inline-block; margin-bottom: 0; margin-right: 1rem"><i class="bi bi-arrow-down-right"></i> {{i['total_receive']}} GB</p>
<p class="text-success" style="text-transform: uppercase; display: inline-block; margin-bottom: 0"><i class="bi bi-arrow-up-right"></i> {{i['total_sent']}} GB</p>
</div>
</div>
</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>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>
<h6><samp class="ml-auto">{{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="w-100"></div>
<div class="col-sm">
<small class="text-muted"><strong>LATEST HANDSHAKE</strong></small>
<h6 style="text-transform: uppercase;">{{i['latest_handshake']}}</h6>
@ -83,20 +96,51 @@
<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="w-100"></div>#}
{# <div class="col-sm">#}
{# <canvas id="{{ i['id'] }}_chart" style="width: 100%" height="200"></canvas>#}
{# </div>#}
{# <script>#}
{# var data = "{{ i['traffic'] }}";#}
{# data = data.replaceAll("&#39;", "\"")#}
{# data = JSON.parse(data)#}
{# y_label = [];#}
{# data_point = [];#}
{# for (var i = 1; i < data.length; i++){#}
{# y_label.push(data[i]['time'])#}
{# data_point.push(data[i]['total_sent'] - data[i-1]['total_sent']);#}
{# }#}
{# var ctx = document.getElementById('{{ i['id'] }}_chart');#}
{# var plot_data =#}
{# {#}
{# labels: y_label,#}
{# datasets:[{#}
{# label: "Traffic",#}
{# data: data_point,#}
{# fill: false,#}
{# borderColor: 'rgb(75, 192, 192)',#}
{# tension: 0.1#}
{# }],#}
{# options: {#}
{# scales: {#}
{# xAxes: [{#}
{# type: 'time',#}
{# ticks: {#}
{# autoSkip: true,#}
{# maxTicksLimit: 12#}
{# }#}
{# }]#}
{# },#}
{# responsive: true#}
{# }#}
{# }#}
{##}
{# var myLineChart = new Chart(ctx, {#}
{# type: 'line',#}
{# data: plot_data#}
{# });#}
{# </script>#}
<div class="w-100"></div>
<div class="col-sm">
<!-- <small class="text-muted"><strong>ACTION</strong></small> -->
<div class="button-group">