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

Commit June 2

This commit is contained in:
Donald Cheng Hong Zou 2021-07-02 13:23:04 -04:00
parent 0a92269456
commit 3aa9eab2bd
9 changed files with 186 additions and 121 deletions

3
.gitignore vendored
View File

@ -8,5 +8,6 @@ src/test.py
tmp tmp
__pycache__ __pycache__
src/wg-dashboard.ini src/wg-dashboard.ini
src/wg-dashboard.ini
src/static/pic.xd src/static/pic.xd
*.conf

View File

@ -17,20 +17,18 @@
## 📣 What's New: Version 2.0.1 ## 📣 What's New: Version 2.1
- Added **Ping** and **Traceroute** tool - Added **Ping** and **Traceroute** tools!
- Adjusted the calculation of data usage on each peers - Adjusted the calculation of data usage on each peers
- Added refresh interval of the dashboard - Added refresh interval of the dashboard
- Bug fixed when no configuration on fresh install ([Bug report](https://github.com/donaldzou/wireguard-dashboard/issues/23#issuecomment-869189672))
- Fixed crash when too many peers ([Bug report](https://github.com/donaldzou/wireguard-dashboard/issues/22#issuecomment-868840564))
<hr> <hr>
### ⚠️ **Update from v1.x.x**
1. Stop the dashboard if it is running.
2. You can use `git pull https://github.com/donaldzou/Wireguard-Dashboard.git v2.0.1` to get the new update inside `Wireguard-Dashboard` directory.
3. Proceed **Step 2 & 3** in the [Install](#-install) step down below.
@ -129,17 +127,31 @@ Since version 2.0, Wireguard Dashboard will be using a configuration file called
All these settings will be able to configure within the dashboard in **Settings** on the sidebar, without changing the actual file. **Except `version` and `auth_req` due to security consideration.** All these settings will be able to configure within the dashboard in **Settings** on the sidebar, without changing the actual file. **Except `version` and `auth_req` due to security consideration.**
## ❓ How to update the dashboard? ## ❓ How to update the dashboard?
```shell 1. Change your directory to `wireguard-dashboard`
cd wireguard-dashboard ```
sudo sh wgd.sh update # Perform update $ cd wireguard-dashboard
sudo sh wgd.sh start # Start dashboard ```
``` 2. Get the newest version
```
$ sudo git pull https://github.com/donaldzou/wireguard-dashboard.git v2.1 --force
```
3. Update and install all python dependencies
```
$ python3 -m pip install -r requirements.txt
```
4. Start the dashboard
```
$ ./wgd.sh start
```
### ⚠️ **Update from v1.x.x**
1. Stop the dashboard if it is running.
2. You can use `git pull https://github.com/donaldzou/Wireguard-Dashboard.git v2.1` to get the new update inside `Wireguard-Dashboard` directory.
3. Proceed **Step 2 & 3** in the [Install](#-install) step down below.
## 🔍 Screenshot ## 🔍 Screenshot

View File

@ -1,9 +1,10 @@
# Python Built-in Library # Python Built-in Library
import os import os
from flask import Flask, request, render_template, redirect, url_for, session, abort, jsonify from flask import Flask, request, render_template, redirect, url_for, session, abort, jsonify
from icmplib import ping, multiping, traceroute, resolve, Host, Hop
import subprocess import subprocess
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
import time
from operator import itemgetter from operator import itemgetter
import secrets import secrets
import hashlib import hashlib
@ -13,9 +14,10 @@ import re
# PIP installed library # PIP installed library
import ifcfg import ifcfg
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
from icmplib import ping, multiping, traceroute, resolve, Host, Hop
# Dashboard Version # Dashboard Version
dashboard_version = 'v2.0' dashboard_version = 'v2.1'
# Dashboard Config Name # Dashboard Config Name
dashboard_conf = 'wg-dashboard.ini' dashboard_conf = 'wg-dashboard.ini'
# Upgrade Required # Upgrade Required
@ -85,35 +87,18 @@ def read_conf_file(config_name):
if i == "[Peer]": if i == "[Peer]":
peer += 1 peer += 1
conf_peer_data["Peers"].append({}) conf_peer_data["Peers"].append({})
else: elif peer > -1:
if len(i) > 0: if len(i) > 0:
tmp = re.split('\s*=\s*', i,1) tmp = re.split('\s*=\s*', i, 1)
if len(tmp) == 2: if len(tmp) == 2:
conf_peer_data["Peers"][peer][tmp[0]] = tmp[1] conf_peer_data["Peers"][peer][tmp[0]] = tmp[1]
f.close()
# Read Configuration File End # Read Configuration File End
return conf_peer_data return conf_peer_data
def get_conf_peers_data(config_name): def get_latest_handshake(config_name, db, peers):
db = TinyDB('db/' + config_name + '.json')
peers = Query()
conf_peer_data = read_conf_file(config_name)
for i in conf_peer_data['Peers']:
if not db.search(peers.id == i['PublicKey']):
db.insert({
"id": i['PublicKey'],
"name": "",
"total_receive": 0,
"total_sent": 0,
"total_data": 0,
"endpoint": 0,
"status": 0,
"latest_handshake": 0,
"allowed_ip": 0,
"traffic": []
})
# Get latest handshakes # Get latest handshakes
try: try:
data_usage = subprocess.check_output("wg show " + config_name + " latest-handshakes", shell=True) data_usage = subprocess.check_output("wg show " + config_name + " latest-handshakes", shell=True)
@ -136,6 +121,7 @@ def get_conf_peers_data(config_name):
db.update({"latest_handshake": "(None)", "status": status}, peers.id == data_usage[count]) db.update({"latest_handshake": "(None)", "status": status}, peers.id == data_usage[count])
count += 2 count += 2
def get_transfer(config_name, db, peers):
# Get transfer # Get transfer
try: try:
data_usage = subprocess.check_output("wg show " + config_name + " transfer", shell=True) data_usage = subprocess.check_output("wg show " + config_name + " transfer", shell=True)
@ -157,7 +143,8 @@ def get_conf_peers_data(config_name):
else: else:
now = datetime.now() now = datetime.now()
ctime = now.strftime("%d/%m/%Y %H:%M:%S") ctime = now.strftime("%d/%m/%Y %H:%M:%S")
traffic.append({"time": ctime, "total_receive": round(total_receive, 4),"total_sent": round(total_sent, 4), traffic.append(
{"time": ctime, "total_receive": round(total_receive, 4), "total_sent": round(total_sent, 4),
"total_data": round(total_receive + total_sent, 4)}) "total_data": round(total_receive + total_sent, 4)})
total_sent = 0 total_sent = 0
total_receive = 0 total_receive = 0
@ -168,6 +155,7 @@ def get_conf_peers_data(config_name):
count += 3 count += 3
def get_endpoint(config_name, db, peers):
# Get endpoint # Get endpoint
try: try:
data_usage = subprocess.check_output("wg show " + config_name + " endpoints", shell=True) data_usage = subprocess.check_output("wg show " + config_name + " endpoints", shell=True)
@ -179,12 +167,47 @@ def get_conf_peers_data(config_name):
db.update({"endpoint": data_usage[count + 1]}, peers.id == data_usage[count]) db.update({"endpoint": data_usage[count + 1]}, peers.id == data_usage[count])
count += 2 count += 2
def get_allowed_ip(config_name, db, peers, conf_peer_data):
# Get allowed ip # Get allowed ip
for i in conf_peer_data["Peers"]: for i in conf_peer_data["Peers"]:
db.update({"allowed_ip": i.get('AllowedIPs', '(None)')}, peers.id == i["PublicKey"]) db.update({"allowed_ip": i.get('AllowedIPs', '(None)')}, peers.id == i["PublicKey"])
def get_conf_peers_data(config_name):
db = TinyDB('db/' + config_name + '.json')
peers = Query()
conf_peer_data = read_conf_file(config_name)
for i in conf_peer_data['Peers']:
if not db.search(peers.id == i['PublicKey']):
db.insert({
"id": i['PublicKey'],
"name": "",
"total_receive": 0,
"total_sent": 0,
"total_data": 0,
"endpoint": 0,
"status": 0,
"latest_handshake": 0,
"allowed_ip": 0,
"traffic": []
})
tic = time.perf_counter()
get_latest_handshake(config_name, db, peers)
get_transfer(config_name, db, peers)
get_endpoint(config_name, db, peers)
get_allowed_ip(config_name, db, peers, conf_peer_data)
toc = time.perf_counter()
print(f"Finish fetching data in {toc - tic:0.4f} seconds")
db.close() db.close()
def get_peers(config_name): def get_peers(config_name):
get_conf_peers_data(config_name) get_conf_peers_data(config_name)
db = TinyDB('db/' + config_name + '.json') db = TinyDB('db/' + config_name + '.json')
@ -243,12 +266,12 @@ def get_conf_list():
if ".conf" in i: if ".conf" in i:
i = i.replace('.conf', '') i = i.replace('.conf', '')
temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)} temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)}
# get_conf_peers_data(i)
if temp['status'] == "running": if temp['status'] == "running":
temp['checked'] = 'checked' temp['checked'] = 'checked'
else: else:
temp['checked'] = "" temp['checked'] = ""
conf.append(temp) conf.append(temp)
if len(conf) > 0:
conf = sorted(conf, key=itemgetter('conf')) conf = sorted(conf, key=itemgetter('conf'))
return conf return conf
@ -266,7 +289,7 @@ def auth_req():
request.endpoint != "signout" and \ request.endpoint != "signout" and \
request.endpoint != "auth" and \ request.endpoint != "auth" and \
"username" not in session: "username" not in session:
print("not loggedin") print("User not loggedin - Attemped access: "+str(request.endpoint))
session['message'] = "You need to sign in first!" session['message'] = "You need to sign in first!"
return redirect(url_for("signin")) return redirect(url_for("signin"))
else: else:
@ -475,6 +498,9 @@ def conf(config_name):
conf_data['checked'] = "checked" conf_data['checked'] = "checked"
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf) config.read(dashboard_conf)
config_list = get_conf_list()
if config_name not in [conf['conf'] for conf in config_list]:
return render_template('index.html', conf=get_conf_list())
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data, dashboard_refresh_interval=int(config.get("Server","dashboard_refresh_interval"))) return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data, dashboard_refresh_interval=int(config.get("Server","dashboard_refresh_interval")))
@ -523,7 +549,7 @@ def add_peer(config_name):
public_key = data['public_key'] public_key = data['public_key']
allowed_ips = data['allowed_ips'] allowed_ips = data['allowed_ips']
keys = get_conf_peer_key(config_name) keys = get_conf_peer_key(config_name)
if public_key is not list: if type(keys) != list:
return config_name+" is not running." return config_name+" is not running."
if public_key in keys: if public_key in keys:
return "Key already exist." return "Key already exist."
@ -531,8 +557,7 @@ def add_peer(config_name):
status = "" status = ""
try: try:
status = subprocess.check_output( status = subprocess.check_output(
"wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True, "wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True, stderr=subprocess.STDOUT)
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)
get_conf_peers_data(config_name) get_conf_peers_data(config_name)
db = TinyDB("db/" + config_name + ".json") db = TinyDB("db/" + config_name + ".json")
@ -548,13 +573,12 @@ def add_peer(config_name):
def remove_peer(config_name): def remove_peer(config_name):
if get_conf_status(config_name) == "stopped": if get_conf_status(config_name) == "stopped":
return "Your need to turn on " + config_name + " first." return "Your need to turn on " + config_name + " first."
db = TinyDB("db/" + config_name + ".json") db = TinyDB("db/" + config_name + ".json")
peers = Query() 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)
if keys is not list: if type(keys) != list:
return config_name+" is not running." return config_name+" is not running."
if delete_key not in keys: if delete_key not in keys:
db.close() db.close()

View File

@ -186,3 +186,13 @@ body {
main{ main{
margin-bottom: 3rem; margin-bottom: 3rem;
} }
/*.add_btn{*/
/* position: fixed;*/
/* bottom: 1.75rem;*/
/* right: 1.75rem;*/
/* z-index: 1000;*/
/* padding: 0.75rem 1.5rem;*/
/* border-radius: 3rem;*/
/* font-size: 1rem;*/
/*}*/

View File

@ -22,13 +22,13 @@
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<form> <form id="add_peer_form">
<div class="form-group"> <div class="form-group">
<label for="public_key">Public Key</label> <label for="public_key">Public Key<code>*</code></label>
<input type="text" class="form-control" id="public_key" aria-describedby="public_key"> <input type="text" class="form-control" id="public_key" aria-describedby="public_key">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="allowed_ips">Allowed IPs</label> <label for="allowed_ips">Allowed IPs<code>*</code></label>
<input type="text" class="form-control" id="allowed_ips"> <input type="text" class="form-control" id="allowed_ips">
</div> </div>
<div class="form-group"> <div class="form-group">
@ -163,7 +163,9 @@
headers:{ headers:{
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
data: JSON.stringify({"public_key":$("#public_key").val(), "allowed_ips": $("#allowed_ips").val(), "name":$("#new_add_name").val()}), data: JSON.stringify({"public_key":$("#public_key").val(),
"allowed_ips": $("#allowed_ips").val(),
"name":$("#new_add_name").val()}),
success: function (response){ success: function (response){
if(response != "true"){ if(response != "true"){
$("#add_peer_alert").html(response+$("#add_peer_alert").html()); $("#add_peer_alert").html(response+$("#add_peer_alert").html());
@ -177,12 +179,18 @@
} }
}) })
var deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), {
keyboard: false
});
$("body").on("click", ".btn-delete-peer", 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);
deleteModal.toggle();
}) })
$("#delete_peer").click(function(){ $("#delete_peer").click(function(){
var peer_id = $(this).attr("peer_id"); var peer_id = $(this).attr("peer_id");
var config = $(this).attr("conf_id"); var config = $(this).attr("conf_id");
@ -199,19 +207,22 @@
$("#remove_peer_alert").removeClass("d-none"); $("#remove_peer_alert").removeClass("d-none");
} }
else{ else{
location.reload(); deleteModal.toggle();
load_data();
$('#alertToast').toast('show');
$('#alertToast .toast-body').html("Peer deleted!");
} }
} }
}) })
}); });
var settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), {
var myModal = new bootstrap.Modal(document.getElementById('setting_modal'), {
keyboard: false keyboard: false
}) })
$("body").on("click", ".btn-setting-peer", function(){ $("body").on("click", ".btn-setting-peer", function(){
myModal.toggle(); settingModal.toggle();
var peer_id = $(this).attr("id"); var peer_id = $(this).attr("id");
$("#save_peer_name").attr("peer_id", peer_id); $("#save_peer_name").attr("peer_id", peer_id);
$.ajax({ $.ajax({
@ -233,6 +244,7 @@
}) })
}); });
$("#save_peer_name").click(function (){ $("#save_peer_name").click(function (){
var peer_id = $(this).attr("peer_id"); var peer_id = $(this).attr("peer_id");
$.ajax({ $.ajax({
@ -243,7 +255,7 @@
}, },
data: JSON.stringify({id: peer_id, name: $("#peer_name_textbox").val()}), data: JSON.stringify({id: peer_id, name: $("#peer_name_textbox").val()}),
success: function (response){ success: function (response){
myModal.toggle(); settingModal.toggle();
load_data(); load_data();
$('#alertToast').toast('show'); $('#alertToast').toast('show');
$('#alertToast .toast-body').html("Name Saved!"); $('#alertToast .toast-body').html("Name Saved!");

View File

@ -56,10 +56,9 @@
<button type="button" class="btn btn-outline-primary btn-sm update_interval" refresh-interval="30000">30s</button> <button type="button" class="btn btn-outline-primary btn-sm update_interval" refresh-interval="30000">30s</button>
<button type="button" class="btn btn-outline-primary btn-sm update_interval" refresh-interval="60000">1m</button> <button type="button" class="btn btn-outline-primary btn-sm update_interval" refresh-interval="60000">1m</button>
</div> </div>
<button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#add_modal"> <button type="button" class="btn btn-primary add_btn btn-sm" data-toggle="modal" data-target="#add_modal">
<i class="bi bi-plus-circle-fill"></i> Peer <i class="bi bi-plus-circle-fill"></i> PEER
</button> </button>
</div> </div>
</div> </div>
@ -111,7 +110,7 @@
<div class="button-group"> <div class="button-group">
<hr> <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-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> <button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="{{i['id']}}" data-toggle="modal"><i class="bi bi-x-circle-fill"></i></button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -6,6 +6,9 @@
{% include "sidebar.html" %} {% include "sidebar.html" %}
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4"> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4">
<h1 class="pb-4 mt-4">Home</h1> <h1 class="pb-4 mt-4">Home</h1>
{% if conf == [] %}
<p class="text-muted">You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".</p>
{% endif %}
{% for i in conf%} {% for i in conf%}
<div class="card mt-3"> <div class="card mt-3">
<div class="card-body"> <div class="card-body">

View File

@ -9,7 +9,7 @@
{% endif %} {% endif %}
{% if session['update'] == "true" %} {% if session['update'] == "true" %}
<li class="nav-item sb-update-li"> <li class="nav-item sb-update-li">
<a class="nav-link sb-update-url" data-toggle="modal" data-target="#update_modal" href="#">New Update Available!<span class="dot dot-running"></span></a> <a class="nav-link sb-update-url" href="https://github.com/donaldzou/wireguard-dashboard#-how-to-update-the-dashboard">New Update Available!<span class="dot dot-running"></span></a>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -50,17 +50,21 @@ update_wgd() {
printf "Are you sure you want to update to the %s? (Y/N): " "$new_ver" printf "Are you sure you want to update to the %s? (Y/N): " "$new_ver"
read up read up
if [ "$up" = "Y" ]; then if [ "$up" = "Y" ]; then
printf "%s\n" "$dashes"
printf "| Shutting down Wireguard Dashboard... |\n" printf "| Shutting down Wireguard Dashboard... |\n"
printf "%s\n" "$dashes"
printf "| Downloading %s from GitHub... |\n" "$new_ver" printf "| Downloading %s from GitHub... |\n" "$new_ver"
printf "%s\n" "$dashes"
git pull https://github.com/donaldzou/wireguard-dashboard.git $new_ver --force > /dev/null 2>&1 git pull https://github.com/donaldzou/wireguard-dashboard.git $new_ver --force > /dev/null 2>&1
printf "| Installing all required python package |\n"
python3 -m pip install -r requirements.txt
printf "| Update Successfully! |\n" printf "| Update Successfully! |\n"
printf "| Dashboard is running... |\n" printf "%s\n" "$dashes"
exec "wgd.sh" "start" printf "| Now you can start the dashboard with >> sh wgd.sh start |\n"
printf "%s\n" "$dashes"
exit 1 exit 1
else else
printf "Cancel update. \n" printf "%s\n" "$dashes"
printf "CANCEL update. \n"
printf "%s\n" "$dashes"
fi fi
} }