Compare commits

...

11 Commits

Author SHA1 Message Date
donaldzou
0efef135d6 Merge branch 'main' of https://github.com/donaldzou/Wireguard-Dashboard into main 2020-10-23 01:31:15 -04:00
donaldzou
ea52529e06 Able to add peer 2020-10-23 01:31:10 -04:00
Donald Zou
259bd325af Update README.md 2020-10-21 20:30:16 -04:00
Donald Zou
faf05bad6a Delete .DS_Store 2020-10-20 10:47:02 -04:00
Donald Zou
0576906907 Delete .DS_Store 2020-10-20 10:46:53 -04:00
donaldzou
8c88440c3e commit 2020-10-20 10:45:29 -04:00
donaldzou
2f327ed49a File arrangement 2020-10-20 10:44:41 -04:00
donaldzou
96af266c38 Update configuration.html 2020-10-19 11:48:08 -04:00
Donald Zou
397e448899 Update README.md 2020-10-18 20:20:02 -04:00
donaldzou
cabb6df477 Update configuration.html 2020-10-18 20:19:41 -04:00
donaldzou
032ea1d967 On/Off Switch 2020-10-18 12:23:38 -04:00
13 changed files with 203 additions and 40 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.vscode/sftp.json src/.vscode/sftp.json
.DS_Store

9
.vscode/sftp.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "My Server",
"host": "38.106.21.18",
"protocol": "sftp",
"port": 22,
"username": "root",
"remotePath": "/root/wireguard-dashboard",
"uploadOnSave": true
}

View File

@@ -1,4 +1,4 @@
# Wireguard-Dashboard # Wireguard Dashboard
## Intro ## Intro
Monitoring Wireguard is not convinient, need to login into server and type wg show. That's why this platform is being created, to view all configurations in a more straight forward way. Monitoring Wireguard is not convinient, need to login into server and type wg show. That's why this platform is being created, to view all configurations in a more straight forward way.
## Installation ## Installation
@@ -15,5 +15,5 @@ Monitoring Wireguard is not convinient, need to login into server and type wg sh
4. Access your server! e.g (http://your_server_ip:10086) 4. Access your server! e.g (http://your_server_ip:10086)
## Example ## Example
![Index Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/static/index.png) ![Index Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/index.png)
![Conf Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/static/configuration.png) ![Conf Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/configuration.png)

View File

@@ -1,14 +1,31 @@
import os import os
from flask import Flask, request, render_template from flask import Flask, request, render_template, redirect, url_for
from tinydb import TinyDB, Query
import subprocess import subprocess
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
from tinydb import TinyDB, Query
import time
import requests
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 = {}
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"
peer_key = peer_key.decode("UTF-8").split()
for i in peer_key: keys.append(i)
return keys
def get_conf_peers_data(config_name): def get_conf_peers_data(config_name):
peer_data = {} peer_data = {}
@@ -27,9 +44,9 @@ 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) peer_data[data_usage[count]]['total_recive'] = int(data_usage[count+1])/(1024**3)
peer_data[data_usage[count]]['total_sent'] = round(int(data_usage[count+2])/(1024**3),4) peer_data[data_usage[count]]['total_sent'] = int(data_usage[count+2])/(1024**3)
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'] = (int(data_usage[count+2])+int(data_usage[count+1]))/(1024**3)
count += 3 count += 3
#Get endpoint #Get endpoint
@@ -50,7 +67,6 @@ 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]))
if minus < b: if minus < b:
peer_data[data_usage[count]]['status'] = "running" peer_data[data_usage[count]]['status'] = "running"
else: else:
@@ -115,6 +131,9 @@ 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)}
if temp['status'] == "running":
temp['checked'] = 'checked'
else: temp['checked'] = ""
conf.append(temp) conf.append(temp)
return conf return conf
@@ -125,15 +144,50 @@ 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 = { conf_data = {
"name": config_name, "name": config_name,
"status": get_conf_status(config_name), "status": get_conf_status(config_name),
"total_data_usage": get_conf_total_data(config_name), "total_data_usage": get_conf_total_data(config_name),
"public_key": get_conf_pub_key(config_name), "public_key": get_conf_pub_key(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),
"checked": ""
} }
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data) if conf_data['status'] == "stopped":
print(conf_data)
return redirect('/')
else:
conf_data['checked'] = "checked"
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data)
@app.route('/switch/<config_name>', methods=['GET'])
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('/')
elif status == "stopped":
try: status = subprocess.check_output("wg-quick up "+config_name, shell=True)
except Exception: return redirect('/')
return redirect('/')
@app.route('/add_peer/<config_name>', methods=['POST'])
def add_peer(config_name):
data = request.get_json()
public_key = data['public_key']
allowed_ips = data['allowed_ips']
keys = get_conf_peer_key(config_name)
if public_key in keys:
return "Key already exist."
else:
try:
status = subprocess.check_output("wg set "+config_name+" peer "+public_key+" allowed-ips "+allowed_ips, shell=True)
status = subprocess.check_output("wg-quick save "+config_name, shell=True)
return "Good"
except Exception: return redirect('/configuration/'+config_name)
app.run(host='0.0.0.0',debug=False, port=10086) app.run(host='0.0.0.0',debug=False, port=10086)

0
src/json/conf.json Normal file
View File

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 455 KiB

After

Width:  |  Height:  |  Size: 455 KiB

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -6,6 +6,8 @@
<title>Wireguard Dashboard</title> <title>Wireguard Dashboard</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<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">
</head> </head>
<body> <body>
@@ -38,9 +40,16 @@
</div> </div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4"> <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="info mt-4">
<small class="text-muted"><strong>CONFIGURATION</strong></small>
<h1 class="mb-3">{{conf_data['name']}}</h1>
<div class="row"> <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"> <div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small> <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> <h6 style="text-transform: uppercase;">{{conf_data['status']}}<span class="dot dot-{{conf_data['status']}}"></span></h6>
@@ -68,7 +77,14 @@
</div> </div>
</div> </div>
<hr> <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="#staticBackdrop">
<strong>ADD PEER</strong>
</button>
</div>
</div> </div>
{% for i in conf_data['peer_data']%} {% for i in conf_data['peer_data']%}
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">
@@ -108,26 +124,93 @@
<small class="text-muted"><strong>TOTAL SENT</strong></small> <small class="text-muted"><strong>TOTAL SENT</strong></small>
<h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['total_sent']}} GB</h6> <h6 style="text-transform: uppercase;">{{conf_data['peer_data'][i]['total_sent']}} GB</h6>
</div> </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-primary btn-sm">QR CODE</button>
<button type="button" class="btn btn-outline-info btn-sm">CONF FILE</button>
<button type="button" class="btn btn-outline-danger btn-sm">DELETE</button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
{%endfor%} {%endfor%}
</main> </main>
</div> </div>
<div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Add a new peer</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="public_key">Public Key</label>
<input type="text" class="form-control" id="public_key" aria-describedby="public_key">
</div>
<div class="form-group">
<label for="allowed_ips">Allowed IPs</label>
<input type="text" class="form-control" id="allowed_ips">
</div>
</form>
</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" conf_id={{conf_data['name']}}>Save</button>
</div>
</div>
</div>
</div>
</body> </body>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
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"
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<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> <script>
setInterval(function(){ $('.switch').change(function() {
location.reload(); if ($(this).prop('checked') == false){
},10000) if (confirm('Are you sure you want to turn off this connection?')){
location.replace("/switch/"+$(this).attr('id'))
}
}
else{
location.replace("/switch/"+$(this).attr('id'))
}
});
$("#save_peer").click(function(){
if ($("#allowed_ips") != "" && $("#public_key") != ""){
var conf = $(this).attr('conf_id')
$.ajax({
method: "POST",
url: "/add_peer/"+conf,
headers:{
"Content-Type": "application/json"
},
data: JSON.stringify({"public_key":$("#public_key").val(), "allowed_ips": $("#allowed_ips").val()}),
success: function (response){
console.log(response);
}
})
}
})
// setInterval(function(){
// location.reload();
// }, 10000)
</script> </script>
</html> </html>

View File

@@ -6,6 +6,7 @@
<title>Wireguard Dashboard</title> <title>Wireguard Dashboard</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<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">
</head> </head>
<body> <body>
@@ -40,10 +41,19 @@
{% 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">
<a href="/configuration/{{i['conf']}}">
<h5 class="card-title">{{i['conf']}}</h5>
</a>
<div class="row"> <div class="row">
<div class="col">
<small class="text-muted"><strong>CONFIGURATION</strong></small>
<a href="/configuration/{{i['conf']}}">
<h5 class="card-title">{{i['conf']}}</h5>
</a>
</div>
<div class="col">
<input class="mt-2 switch" id="{{i['conf']}}" type="checkbox" data-toggle="toggle" {{i['checked']}} data-size="sm">
</div>
<div class="w-100"></div>
<div class="col-sm"> <div class="col-sm">
<small class="text-muted"><strong>STATUS</strong></small> <small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;">{{i['status']}}<span class="dot dot-{{i['status']}}"></span></h6> <h6 style="text-transform: uppercase;">{{i['status']}}<span class="dot dot-{{i['status']}}"></span></h6>
@@ -52,6 +62,8 @@
<small class="text-muted"><strong>PUBLIC KEY</strong></small> <small class="text-muted"><strong>PUBLIC KEY</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{i['public_key']}}</samp></h6> <h6 style="text-transform: uppercase;"><samp>{{i['public_key']}}</samp></h6>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -67,12 +79,17 @@
<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> <script>
// $.get("/get_conf", function(data, status){ $('.switch').change(function() {
// for (var i = 0; i < data['data'].length; i++){ if ($(this).prop('checked') == false){
// $(".nav").append('<li class="nav-item"><a class="nav-link" href="/conf/'+data['data'][i]['conf']+'">'+data['data'][i]['conf']+'</a></li>'); if (confirm('Are you sure you want to turn off this connection?')){
// $("main").append('<div class="card mt-3"><div class="card-body"><a href="/conf/'+data['data'][i]['conf']+'"><h5 class="card-title">'+data['data'][i]['conf']+'</h5></a><h6 class="card-subtitle mb-2 text-muted">Status: '+data['data'][i]['status']+'<span class="dot dot-'+data['data'][i]['status']+'"></span></h6></div></div>') location.replace("/switch/"+$(this).attr('id'))
// } }
// }); }
else{
location.replace("/switch/"+$(this).attr('id'))
}
});
</script> </script>
</html> </html>

4
src/test.py Normal file
View File

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

View File

@@ -1,5 +0,0 @@
import os
import subprocess
try: status = subprocess.check_output("wg show wg0", shell=True)
except Exception: print("false")
else:print(status.decode("UTF-8"))