mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-16 12:30:12 +01:00
Still finalizing everything
This commit is contained in:
parent
6d56967a0f
commit
9ff7198602
132
src/dashboard.py
132
src/dashboard.py
@ -1,7 +1,8 @@
|
||||
"""
|
||||
< WGDashboard > - by Donald Zou [https://github.com/donaldzou]
|
||||
< WGDashboard > - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]
|
||||
Under Apache-2.0 License
|
||||
"""
|
||||
|
||||
# TODO: Testing migrate to sqlite
|
||||
import sqlite3
|
||||
from flask import g
|
||||
@ -130,7 +131,7 @@ def read_conf_file(config_name):
|
||||
}
|
||||
peers_start = 0
|
||||
for i in range(len(file)):
|
||||
if not regex_match("#(.*)", file[i]):
|
||||
if not regex_match("#(.*)", file[i]) and regex_match(";(.*)", file[i]):
|
||||
if file[i] == "[Peer]":
|
||||
peers_start = i
|
||||
break
|
||||
@ -143,7 +144,7 @@ def read_conf_file(config_name):
|
||||
conf_peers = file[peers_start:]
|
||||
peer = -1
|
||||
for i in conf_peers:
|
||||
if not regex_match("#(.*)", i):
|
||||
if not regex_match("#(.*)", i) and not regex_match(";(.*)", i):
|
||||
if i == "[Peer]":
|
||||
peer += 1
|
||||
conf_peer_data["Peers"].append({})
|
||||
@ -206,7 +207,6 @@ def get_transfer(config_name):
|
||||
if len(cur_i) > 0:
|
||||
total_sent = cur_i[0][1]
|
||||
total_receive = cur_i[0][0]
|
||||
# traffic = cur_i[0]['traffic']
|
||||
cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4)
|
||||
cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4)
|
||||
if cur_i[0][4] == "running":
|
||||
@ -214,13 +214,11 @@ def get_transfer(config_name):
|
||||
total_sent = cur_total_sent
|
||||
total_receive = cur_total_receive
|
||||
else:
|
||||
now = datetime.now()
|
||||
ctime = now.strftime("%d/%m/%Y %H:%M:%S")
|
||||
cumu_receive = cur_i[0][2] + total_receive
|
||||
cumu_sent = cur_i[0][3] + total_sent
|
||||
cumulative_receive = cur_i[0][2] + total_receive
|
||||
cumulative_sent = cur_i[0][3] + total_sent
|
||||
g.cur.execute("UPDATE %s SET cumu_receive = %f, cumu_sent = %f, cumu_data = %f WHERE id = '%s'" %
|
||||
(config_name, round(cumu_receive, 4), round(cumu_sent, 4),
|
||||
round(cumu_sent + cumu_receive, 4), data_usage[i][0]))
|
||||
(config_name, round(cumulative_receive, 4), round(cumulative_sent, 4),
|
||||
round(cumulative_sent + cumulative_receive, 4), data_usage[i][0]))
|
||||
total_sent = 0
|
||||
total_receive = 0
|
||||
g.cur.execute("UPDATE %s SET total_receive = %f, total_sent = %f, total_data = %f WHERE id = '%s'" %
|
||||
@ -258,11 +256,14 @@ def get_allowed_ip(conf_peer_data, config_name):
|
||||
def get_all_peers_data(config_name):
|
||||
conf_peer_data = read_conf_file(config_name)
|
||||
config = get_dashboard_conf()
|
||||
for i in conf_peer_data['Peers']:
|
||||
result = g.cur.execute("SELECT * FROM %s WHERE id='%s'" % (config_name, i["PublicKey"])).fetchall()
|
||||
failed_index = []
|
||||
for i in range(len(conf_peer_data['Peers'])):
|
||||
if "PublicKey" in conf_peer_data['Peers'][i].keys():
|
||||
result = g.cur.execute(
|
||||
"SELECT * FROM %s WHERE id='%s'" % (config_name, conf_peer_data['Peers'][i]["PublicKey"])).fetchall()
|
||||
if len(result) == 0:
|
||||
new_data = {
|
||||
"id": i['PublicKey'],
|
||||
"id": conf_peer_data['Peers'][i]['PublicKey'],
|
||||
"private_key": "",
|
||||
"DNS": config.get("Peers", "peer_global_DNS"),
|
||||
"endpoint_allowed_ip": config.get("Peers", "peer_endpoint_allowed_ip"),
|
||||
@ -283,14 +284,21 @@ def get_all_peers_data(config_name):
|
||||
"remote_endpoint": config.get("Peers", "remote_endpoint"),
|
||||
"preshared_key": ""
|
||||
}
|
||||
if "PresharedKey" in i.keys():
|
||||
new_data["preshared_key"] = i["PresharedKey"]
|
||||
g.cur.execute(
|
||||
"INSERT INTO " + config_name + " VALUES (:id, :private_key, :DNS, :endpoint_allowed_ip, :name, :total_receive, :total_sent, :total_data, :endpoint, :status, :latest_handshake, :allowed_ip, :cumu_receive, :cumu_sent, :cumu_data, :mtu, :keepalive, :remote_endpoint, :preshared_key)",
|
||||
new_data)
|
||||
if "PresharedKey" in conf_peer_data['Peers'][i].keys():
|
||||
new_data["preshared_key"] = conf_peer_data['Peers'][i]["PresharedKey"]
|
||||
sql = f"""
|
||||
INSERT INTO {config_name}
|
||||
VALUES (:id, :private_key, :DNS, :endpoint_allowed_ip, :name, :total_receive, :total_sent,
|
||||
:total_data, :endpoint, :status, :latest_handshake, :allowed_ip, :cumu_receive, :cumu_sent,
|
||||
:cumu_data, :mtu, :keepalive, :remote_endpoint, :preshared_key);
|
||||
"""
|
||||
g.cur.execute(sql, new_data)
|
||||
else:
|
||||
pass
|
||||
print("Trying to parse a peer doesn't have public key...")
|
||||
failed_index.append(i)
|
||||
|
||||
for i in failed_index:
|
||||
conf_peer_data['Peers'].pop(i)
|
||||
# Remove peers no longer exist in WireGuard configuration file
|
||||
db_key = list(map(lambda a: a[0], g.cur.execute("SELECT id FROM %s" % config_name)))
|
||||
wg_key = list(map(lambda a: a['PublicKey'], conf_peer_data['Peers']))
|
||||
@ -314,9 +322,6 @@ def get_peers(config_name, search, sort_t):
|
||||
tic = time.perf_counter()
|
||||
col = g.cur.execute("PRAGMA table_info(" + config_name + ")").fetchall()
|
||||
col = [a[1] for a in col]
|
||||
# col = ['id', 'private_key', 'DNS', 'endpoint_allowed_ip', 'name', 'total_receive',
|
||||
# 'total_sent', 'total_data', 'endpoint', 'status', 'latest_handshake', 'allowed_ip',
|
||||
# 'cumu_receive', 'cumu_sent', 'cumu_data', 'mtu', 'keepalive', 'remote_endpoint', 'preshared_key']
|
||||
get_all_peers_data(config_name)
|
||||
if len(search) == 0:
|
||||
data = g.cur.execute("SELECT * FROM " + config_name).fetchall()
|
||||
@ -326,7 +331,8 @@ def get_peers(config_name, search, sort_t):
|
||||
data = g.cur.execute(sql).fetchall()
|
||||
result = [{col[i]: data[k][i] for i in range(len(col))} for k in range(len(data))]
|
||||
if sort_t == "allowed_ip":
|
||||
result = sorted(result, key=lambda d: ipaddress.ip_network(d[sort_t].split(",")[0]))
|
||||
result = sorted(result, key=lambda d: ipaddress.ip_network(
|
||||
"0.0.0.0/0" if d[sort_t].split(",")[0] == "(None)" else d[sort_t].split(",")[0]))
|
||||
else:
|
||||
result = sorted(result, key=lambda d: d[sort_t])
|
||||
toc = time.perf_counter()
|
||||
@ -343,7 +349,7 @@ def get_conf_pub_key(config_name):
|
||||
pub = subprocess.run(f"echo '{pri}' | wg pubkey", check=True, shell=True, capture_output=True).stdout
|
||||
conf.clear()
|
||||
return pub.decode().strip("\n")
|
||||
except configparser.NoSectionError as e:
|
||||
except configparser.NoSectionError:
|
||||
return ""
|
||||
|
||||
|
||||
@ -417,8 +423,7 @@ def get_conf_list():
|
||||
|
||||
# Generate private key
|
||||
def gen_private_key():
|
||||
gen = subprocess.check_output('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt',
|
||||
shell=True)
|
||||
subprocess.run('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt', shell=True)
|
||||
with open('private_key.txt', encoding='utf-8') as file_object:
|
||||
private_key = file_object.readline().strip()
|
||||
with open('public_key.txt', encoding='utf-8') as file_object:
|
||||
@ -432,7 +437,7 @@ def gen_public_key(private_key):
|
||||
with open('private_key.txt', 'w', encoding='utf-8') as file_object:
|
||||
file_object.write(private_key)
|
||||
try:
|
||||
check = subprocess.check_output("wg pubkey < private_key.txt > public_key.txt", shell=True)
|
||||
subprocess.check_output("wg pubkey < private_key.txt > public_key.txt", shell=True)
|
||||
with open('public_key.txt', encoding='utf-8') as file_object:
|
||||
public_key = file_object.readline().strip()
|
||||
os.remove('private_key.txt')
|
||||
@ -464,7 +469,7 @@ def check_repeat_allowed_ip(public_key, ip, config_name):
|
||||
return {'status': 'failed', 'msg': 'Peer does not exist'}
|
||||
else:
|
||||
existed_ip = g.cur.execute("SELECT COUNT(*) FROM " +
|
||||
config_name + " WHERE id != ? AND allowed_ip LIKE '" + ip + "/%'", (public_key,))\
|
||||
config_name + " WHERE id != ? AND allowed_ip LIKE '" + ip + "/%'", (public_key,)) \
|
||||
.fetchone()
|
||||
if existed_ip[0] != 0:
|
||||
return {'status': 'failed', 'msg': "Allowed IP already taken by another peer."}
|
||||
@ -486,12 +491,12 @@ def f_available_ips(config_name):
|
||||
add = i[0].split(",")
|
||||
for k in add:
|
||||
a, s = k.split("/")
|
||||
existed.append(ipaddress.ip_address(a))
|
||||
existed.append(ipaddress.ip_address(a.strip()))
|
||||
available = list(ipaddress.ip_network(address[0], False).hosts())
|
||||
for i in existed:
|
||||
try:
|
||||
available.remove(i)
|
||||
except ValueError as e:
|
||||
except ValueError:
|
||||
pass
|
||||
available = [str(i) for i in available]
|
||||
return available
|
||||
@ -527,7 +532,7 @@ def auth_req():
|
||||
request.endpoint != "signout" and \
|
||||
request.endpoint != "auth" and \
|
||||
"username" not in session:
|
||||
print("User not loggedin - Attemped access: " + str(request.endpoint))
|
||||
print("User not signed in - Attempted access: " + str(request.endpoint))
|
||||
if request.endpoint != "index":
|
||||
session['message'] = "You need to sign in first!"
|
||||
else:
|
||||
@ -890,6 +895,9 @@ def add_peer_bulk(config_name):
|
||||
dns_addresses = data['DNS']
|
||||
enable_preshared_key = data["enable_preshared_key"]
|
||||
amount = data['amount']
|
||||
config_interface = read_conf_file_interface(config_name)
|
||||
if "Address" not in config_interface:
|
||||
return "Configuration must have an IP address."
|
||||
if not amount.isdigit() or int(amount) < 1:
|
||||
return "Amount must be integer larger than 0"
|
||||
amount = int(amount)
|
||||
@ -902,6 +910,8 @@ def add_peer_bulk(config_name):
|
||||
if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit():
|
||||
return "Persistent Keepalive format is not correct."
|
||||
ips = f_available_ips(config_name)
|
||||
if amount > len(ips):
|
||||
return f"Cannot create more than {len(ips)} peers."
|
||||
wg_command = ["wg", "set", config_name]
|
||||
sql_command = []
|
||||
for i in range(amount):
|
||||
@ -939,7 +949,6 @@ def add_peer_bulk(config_name):
|
||||
return exc.output.strip()
|
||||
|
||||
|
||||
|
||||
# Add peer
|
||||
@app.route('/add_peer/<config_name>', methods=['POST'])
|
||||
def add_peer(config_name):
|
||||
@ -1010,7 +1019,7 @@ def remove_peer(config_name):
|
||||
for delete_key in delete_keys:
|
||||
if delete_key not in keys:
|
||||
return "This key does not exist"
|
||||
sql_command.append("DELETE FROM " + config_name + " WHERE id = '"+delete_key+"';")
|
||||
sql_command.append("DELETE FROM " + config_name + " WHERE id = '" + delete_key + "';")
|
||||
wg_command.append("peer")
|
||||
wg_command.append(delete_key)
|
||||
wg_command.append("remove")
|
||||
@ -1154,10 +1163,55 @@ def generate_qrcode(config_name):
|
||||
return redirect("/configuration/" + config_name)
|
||||
|
||||
|
||||
# Download all configuration file
|
||||
@app.route('/download_all/<config_name>', methods=['GET'])
|
||||
def download_all(config_name):
|
||||
get_peer = g.cur.execute(
|
||||
"SELECT private_key, allowed_ip, DNS, mtu, endpoint_allowed_ip, keepalive, preshared_key, name FROM "
|
||||
+ config_name + " WHERE private_key != ''").fetchall()
|
||||
config = get_dashboard_conf()
|
||||
data = []
|
||||
public_key = get_conf_pub_key(config_name)
|
||||
listen_port = get_conf_listen_port(config_name)
|
||||
endpoint = config.get("Peers", "remote_endpoint") + ":" + listen_port
|
||||
for peer in get_peer:
|
||||
private_key = peer[0]
|
||||
allowed_ip = peer[1]
|
||||
dns_addresses = peer[2]
|
||||
mtu_value = peer[3]
|
||||
endpoint_allowed_ip = peer[4]
|
||||
keepalive = peer[5]
|
||||
preshared_key = peer[6]
|
||||
filename = peer[7]
|
||||
if len(filename) == 0:
|
||||
filename = "Untitled_Peer"
|
||||
else:
|
||||
filename = peer[7]
|
||||
# Clean filename
|
||||
illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3",
|
||||
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
||||
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
||||
for i in illegal_filename:
|
||||
filename = filename.replace(i, "")
|
||||
if len(filename) == 0:
|
||||
filename = "Untitled_Peer"
|
||||
filename = "".join(filename.split(' '))
|
||||
filename = filename + "_" + config_name
|
||||
psk = ""
|
||||
if preshared_key != "":
|
||||
psk = "\nPresharedKey = " + preshared_key
|
||||
|
||||
return_data = "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nDNS = " + \
|
||||
dns_addresses + "\nMTU = " + str(mtu_value) + "\n\n[Peer]\nPublicKey = " + \
|
||||
public_key + "\nAllowedIPs = " + endpoint_allowed_ip + "\nEndpoint = " + \
|
||||
endpoint + "\nPersistentKeepalive = " + str(keepalive) + psk
|
||||
data.append({"filename": f"{filename}.conf", "content": return_data})
|
||||
return jsonify({"status": True, "peers": data, "filename": f"{config_name}.zip"})
|
||||
|
||||
|
||||
# Download configuration file
|
||||
@app.route('/download/<config_name>', methods=['GET'])
|
||||
def download(config_name):
|
||||
print(request.headers.get('User-Agent'))
|
||||
peer_id = request.args.get('id')
|
||||
get_peer = g.cur.execute(
|
||||
"SELECT private_key, allowed_ip, DNS, mtu, endpoint_allowed_ip, keepalive, preshared_key, name FROM "
|
||||
@ -1195,15 +1249,13 @@ def download(config_name):
|
||||
if preshared_key != "":
|
||||
psk = "\nPresharedKey = " + preshared_key
|
||||
|
||||
def generate():
|
||||
yield "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nDNS = " + \
|
||||
return_data = "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nDNS = " + \
|
||||
dns_addresses + "\nMTU = " + str(mtu_value) + "\n\n[Peer]\nPublicKey = " + \
|
||||
public_key + "\nAllowedIPs = " + endpoint_allowed_ip + "\nEndpoint = " + \
|
||||
endpoint + "\nPersistentKeepalive = " + str(keepalive) + psk
|
||||
|
||||
return app.response_class(generate(), mimetype='text/conf',
|
||||
headers={"Content-Disposition": "attachment;filename=" + filename + ".conf"})
|
||||
return redirect("/configuration/" + config_name)
|
||||
return jsonify({"status": True, "filename": f"{filename}.conf", "content": return_data})
|
||||
return jsonify({"status": False, "filename": "", "content": ""})
|
||||
|
||||
|
||||
# Switch peer display mode
|
||||
@ -1291,7 +1343,7 @@ Dashboard Initialization
|
||||
def init_dashboard():
|
||||
# Set Default INI File
|
||||
if not os.path.isfile(DASHBOARD_CONF):
|
||||
conf_file = open(DASHBOARD_CONF, "w+")
|
||||
open(DASHBOARD_CONF, "w+").close()
|
||||
config = get_dashboard_conf()
|
||||
# Defualt dashboard account setting
|
||||
if "Account" not in config:
|
||||
|
26
src/db/wg1.conf.backup
Normal file
26
src/db/wg1.conf.backup
Normal file
@ -0,0 +1,26 @@
|
||||
[Interface]
|
||||
Address = 10.200.100.1/24
|
||||
PostUp = iptables -A FORWARD -i wg1 -j ACCEPT; iptables -A FORWARD -o wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE;tc qdisc add dev wg1 root tbf rate 50000kbit buffer 1600 limit 50000
|
||||
PreDown = tc qdisc del dev wg1 root
|
||||
PostDown = iptables -D FORWARD -i wg1 -j ACCEPT; iptables -D FORWARD -o wg1 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE;
|
||||
ListenPort = 60945
|
||||
PrivateKey = 8DsSMli3okgUx5frKbFQ0fMW5ZMyqyxOdOW7+g21L18=
|
||||
|
||||
[Peer]
|
||||
PublicKey = aXsYmR73LEuwVOJeqUjlsWbWPyvJPm3lg3zh7WkruWg=
|
||||
PresharedKey = GISQ6z6GMLocJQgdYOfi2XX7NQWkZBPPFiueRYLqnJE=
|
||||
AllowedIPs = 10.200.100.2/32
|
||||
|
||||
[Peer]
|
||||
PublicKey = FxXXNXoKZcBNyZbq0nFsmBC5YM+7up3a4bYGU6q900w=
|
||||
PresharedKey = dqp44vullLVZQhIYE2VaY6WFQNfahnHum5kq3sWPsSc=
|
||||
AllowedIPs = 10.200.100.3/32
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Peer]
|
||||
PublicKey = FxXXNXoKZcBNyZbq0nFsmBC5YM+7up3a4bYGU6q900w=
|
||||
PresharedKey = dqp44vullLVZQhIYE2VaY6WFQNfahnHum5kq3sWPsSc=
|
||||
AllowedIPs = 10.200.100.3/32
|
@ -472,3 +472,34 @@ main{
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.no-response{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
background: #000000ba;
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: all 1s ease-in-out;
|
||||
}
|
||||
|
||||
.no-response.active{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.no-response.active.show{
|
||||
opacity: 100;
|
||||
}
|
||||
|
||||
.no-response .container > *{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-responding{
|
||||
transition: all 1s ease-in-out;
|
||||
filter: blur(10px);
|
||||
}
|
2
src/static/css/dashboard.min.css
vendored
2
src/static/css/dashboard.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,5 +1,142 @@
|
||||
$("[data-toggle='tooltip']").tooltip()
|
||||
$("[data-toggle='popover']").popover()
|
||||
/**
|
||||
* configuration.js - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]
|
||||
* Under Apache-2.0 License
|
||||
*/
|
||||
|
||||
/**
|
||||
* This will load peers data from server
|
||||
* @param search
|
||||
*/
|
||||
function load_data(search){
|
||||
startProgressBar();
|
||||
let result = '';
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/get_config/"+conf_name+"?search="+encodeURIComponent(search),
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
success: function (response){
|
||||
removeNoResponding();
|
||||
peers = response.peer_data;
|
||||
if (response.listen_port === "" && response.status === "stopped"){
|
||||
$("config_info_alert").append('<div class="alert alert-warning" role="alert">Peer QR Code and configuration file download required a specified <strong>Listen Port</strong>.</div>');
|
||||
}
|
||||
if (response.conf_address === "N/A"){
|
||||
$("config_info_alert").append('<div class="alert alert-warning" role="alert">Configuration <strong>Address</strong> need to be specified to have peers connect to it.</div>');
|
||||
}
|
||||
let $conf_status_btn = $("#conf_status_btn");
|
||||
if (response.checked === "checked"){
|
||||
$conf_status_btn.html('<a href="#" id="'+response.name+'" '+response.checked+' class="switch text-primary"><i class="bi bi-toggle2-on"></i> ON</a>');
|
||||
}else{
|
||||
$conf_status_btn.html('<a href="#" id="'+response.name+'" '+response.checked+' class="switch text-primary"><i class="bi bi-toggle2-off"></i> OFF</a>');
|
||||
}
|
||||
$("#sort_by_dropdown option").removeAttr("selected");
|
||||
$("#sort_by_dropdown option[value="+response.sort_tag+"]").attr("selected", "selected");
|
||||
$(".interval-btn-group button").removeClass("active");
|
||||
$("button[data-refresh-interval="+response.dashboard_refresh_interval+"]").addClass("active");
|
||||
$(".display-btn-group button").removeClass("active");
|
||||
$("button[data-display-mode="+response.peer_display_mode+"]").addClass("active");
|
||||
|
||||
|
||||
|
||||
$("#conf_status").html(response.status+'<span class="dot dot-'+response.status+'"></span>');
|
||||
$("#conf_connected_peers").html(response.running_peer);
|
||||
$("#conf_total_data_usage").html(response.total_data_usage[0] +" GB");
|
||||
$("#conf_total_data_received").html(response.total_data_usage[2] +" GB");
|
||||
$("#conf_total_data_sent").html(response.total_data_usage[1]+" GB");
|
||||
$("#conf_public_key").html(response.public_key);
|
||||
$("#conf_listen_port").html(response.listen_port === "" ? "N/A":response.listen_port);
|
||||
$("#conf_address").html(response.listen_port);
|
||||
$(".info h6").removeClass("info_loading");
|
||||
$conf_status_btn.removeClass("info_loading");
|
||||
|
||||
|
||||
|
||||
if (response.peer_data.length === 0){
|
||||
$(".peer_list").html('<div class="col-12" style="text-align: center; margin-top: 1.5rem"><h3 class="text-muted">Oops! No peers found ‘︿’</h3></div>');
|
||||
}else{
|
||||
let display_mode = response.peer_display_mode === "list" ? "col-12" : "col-sm-6 col-lg-4";
|
||||
response.peer_data.forEach(function(peer){
|
||||
let total_r = 0;
|
||||
let total_s = 0;
|
||||
total_r += peer.cumu_receive;
|
||||
total_s += peer.cumu_sent;
|
||||
let spliter = '<div class="w-100"></div>';
|
||||
let peer_name =
|
||||
'<div class="col-sm display" style="display: flex; align-items: center; margin-bottom: 0.2rem">' +
|
||||
'<h5 style="margin: 0;">'+ (peer.name === "" ? "Untitled" : peer.name) +'</h5>' +
|
||||
'<h6 style="text-transform: uppercase; margin: 0; margin-left: auto !important;"><span class="dot dot-'+peer.status+'" style="margin-left: auto !important;" data-toggle="tooltip" data-placement="left" title="Peer Connected"></span></h6>' +
|
||||
'</div>';
|
||||
let peer_transfer = '<div class="col-12 peer_data_group" style="text-align: right; display: flex; margin-bottom: 0.5rem"><p class="text-primary" style="text-transform: uppercase; margin-bottom: 0; margin-right: 1rem"><small><i class="bi bi-arrow-down-right"></i> '+ roundN(peer.total_receive + total_r, 4) +' GB</small></p> <p class="text-success" style="text-transform: uppercase; margin-bottom: 0"><small><i class="bi bi-arrow-up-right"></i> '+ roundN(peer.total_sent + total_s, 4) +' GB</small></p> </div>';
|
||||
let peer_key = '<div class="col-sm"><small class="text-muted" style="display: flex"><strong>PEER</strong><strong style="margin-left: auto!important; opacity: 0; transition: 0.2s ease-in-out" class="text-primary">CLICK TO COPY</strong></small> <h6><samp class="ml-auto key">'+peer.id+'</samp></h6></div>';
|
||||
let peer_allowed_ip = '<div class="col-sm"><small class="text-muted"><strong>ALLOWED IP</strong></small><h6 style="text-transform: uppercase;">'+peer.allowed_ip+'</h6></div>';
|
||||
let peer_latest_handshake = '<div class="col-sm"> <small class="text-muted"><strong>LATEST HANDSHAKE</strong></small> <h6 style="text-transform: uppercase;">'+peer.latest_handshake+'</h6> </div>';
|
||||
let peer_endpoint = '<div class="col-sm"><small class="text-muted"><strong>END POINT</strong></small><h6 style="text-transform: uppercase;">'+peer.endpoint+'</h6></div>';
|
||||
let peer_control = '<div class="col-sm"><hr><div class="button-group" style="display:flex"><button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" id="'+peer.id+'" data-toggle="modal"><i class="bi bi-gear-fill" data-toggle="tooltip" data-placement="bottom" title="Peer Settings"></i></button> <button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="'+peer.id+'" data-toggle="modal"><i class="bi bi-x-circle-fill" data-toggle="tooltip" data-placement="bottom" title="Delete Peer"></i></button>';
|
||||
if (peer.private_key !== ""){
|
||||
peer_control += '<div class="share_peer_btn_group" style="margin-left: auto !important; display: inline"><button type="button" class="btn btn-outline-success btn-qrcode-peer btn-control" img_src="/qrcode/'+response.name+'?id='+encodeURIComponent(peer.id)+'"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 19px;" fill="#28a745"><path d="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zM13 3v8h8V3h-8zm6 6h-4V5h4v4zM13 13h2v2h-2zM15 15h2v2h-2zM13 17h2v2h-2zM17 17h2v2h-2zM19 19h2v2h-2zM15 19h2v2h-2zM17 13h2v2h-2zM19 15h2v2h-2z"/></svg></button><a href="/download/'+response.name+'?id='+encodeURIComponent(peer.id)+'" class="btn btn-outline-info btn-download-peer btn-control"><i class="bi bi-download"></i></a></div>';
|
||||
}
|
||||
peer_control += '</div>';
|
||||
let html = '<div class="'+display_mode+'" data-id="'+peer.id+'">' +
|
||||
'<div class="card mb-3 card-'+peer.status+'">' +
|
||||
'<div class="card-body">' +
|
||||
'<div class="row">' +
|
||||
peer_name +
|
||||
spliter +
|
||||
peer_transfer +
|
||||
peer_key +
|
||||
peer_allowed_ip +
|
||||
peer_latest_handshake +
|
||||
spliter +
|
||||
peer_endpoint +
|
||||
spliter +
|
||||
peer_control +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div></div>';
|
||||
result += html;
|
||||
});
|
||||
$(".peer_list").html(result);
|
||||
if (response.dashboard_refresh_interval !== load_interval){
|
||||
load_interval = response.dashboard_refresh_interval;
|
||||
clearInterval(load_timeout);
|
||||
load_timeout = setInterval(function (){
|
||||
load_data($('#search_peer_textbox').val());
|
||||
}, response.dashboard_refresh_interval);
|
||||
}
|
||||
}
|
||||
$(".dot.dot-running").attr("title","Peer Connected").tooltip();
|
||||
$(".dot.dot-stopped").attr("title","Peer Disconnected").tooltip();
|
||||
$("i[data-toggle='tooltip']").tooltip();
|
||||
endProgressBar();
|
||||
}
|
||||
}).fail(function(){
|
||||
noResponding();
|
||||
});
|
||||
}
|
||||
|
||||
function noResponding(){
|
||||
$(".no-response").addClass("active");
|
||||
setTimeout(function (){
|
||||
$(".no-response").addClass("show");
|
||||
$("#right_body").addClass("no-responding");
|
||||
$(".navbar").addClass("no-responding");
|
||||
},10);
|
||||
}
|
||||
|
||||
function removeNoResponding(){
|
||||
$(".no-response").removeClass("show");
|
||||
$("#right_body").removeClass("no-responding");
|
||||
$(".navbar").removeClass("no-responding");
|
||||
setTimeout(function (){
|
||||
$(".no-response").removeClass("active");
|
||||
},1010);
|
||||
}
|
||||
|
||||
$("[data-toggle='tooltip']").tooltip();
|
||||
$("[data-toggle='popover']").popover();
|
||||
let $body = $("body");
|
||||
let $progress_bar = $(".progress-bar");
|
||||
let available_ips = [];
|
||||
@ -221,11 +358,33 @@ function clean_ip(val){
|
||||
return clean_ip.filter(Boolean).join(",");
|
||||
}
|
||||
|
||||
let bulk_add_peers = () => {
|
||||
|
||||
$("#new_add_amount").on("keyup", function(){
|
||||
let $bulk_amount_validation = $("#bulk_amount_validation");
|
||||
// $(this).removeClass("is-valid").addClass("is-invalid");
|
||||
if ($(this).val().length > 0){
|
||||
if (isNaN($(this).val())){
|
||||
$(this).removeClass("is-valid").addClass("is-invalid");
|
||||
$bulk_amount_validation.html("Please enter a valid integer");
|
||||
}else if ($(this).val() > available_ips.length){
|
||||
$(this).removeClass("is-valid").addClass("is-invalid");
|
||||
$bulk_amount_validation.html(`Cannot create more than ${available_ips.length} peers.`);
|
||||
}else if ($(this).val() < 1){
|
||||
$(this).removeClass("is-valid").addClass("is-invalid");
|
||||
$bulk_amount_validation.html("Please enter at least 1 or more.");
|
||||
}else{
|
||||
$(this).removeClass("is-invalid").addClass("is-valid");
|
||||
}
|
||||
}else{
|
||||
$(this).removeClass("is-invalid").removeClass("is-valid");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function bulk_add_peers() {
|
||||
let $new_add_amount = $("#new_add_amount");
|
||||
$save_peer.attr("disabled","disabled");
|
||||
$save_peer.html("Adding "+$new_add_amount.val()+" peers...");
|
||||
|
||||
let $new_add_DNS = $("#new_add_DNS");
|
||||
$new_add_DNS.val(clean_ip($new_add_DNS.val()));
|
||||
let $new_add_endpoint_allowed_ip = $("#new_add_endpoint_allowed_ip");
|
||||
@ -234,11 +393,13 @@ let bulk_add_peers = () => {
|
||||
let $new_add_keep_alive = $("#new_add_keep_alive");
|
||||
let $enable_preshare_key = $("#enable_preshare_key");
|
||||
let data_list = [$new_add_DNS, $new_add_endpoint_allowed_ip,$new_add_MTU, $new_add_keep_alive];
|
||||
if ($new_add_amount.val() > 0){
|
||||
if ($new_add_amount.val() > 0 && !$new_add_amount.hasClass("is-invalid")){
|
||||
if ($new_add_DNS.val() !== "" && $new_add_endpoint_allowed_ip.val() !== ""){
|
||||
let conf = $save_peer.attr('conf_id');
|
||||
let keys = [];
|
||||
for (let i = 0; i < $new_add_amount.val(); i++) keys.push(wireguard.generateKeypair());
|
||||
for (let i = 0; i < $new_add_amount.val(); i++) {
|
||||
keys.push(wireguard.generateKeypair());
|
||||
}
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/add_peer_bulk/"+conf,
|
||||
@ -269,16 +430,14 @@ let bulk_add_peers = () => {
|
||||
$addModal.toggle();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}else{
|
||||
$("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none");
|
||||
$save_peer.removeAttr("disabled");
|
||||
$save_peer.html("Add");
|
||||
}
|
||||
}else{
|
||||
$("#add_peer_alert").html("Please enter 1 or more amount.").removeClass("d-none");
|
||||
$save_peer.removeAttr("disabled");
|
||||
$save_peer.html("Add");
|
||||
$save_peer.removeAttr("disabled").html("Add");
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,7 +445,9 @@ let bulk_add_peers = () => {
|
||||
$save_peer.on("click",function(){
|
||||
let $bulk_add = $("#bulk_add");
|
||||
if ($bulk_add.prop("checked")){
|
||||
if (!$("#new_add_amount").hasClass("is-invalid")){
|
||||
bulk_add_peers()
|
||||
}
|
||||
}else {
|
||||
let $public_key = $("#public_key");
|
||||
let $private_key = $("#private_key");
|
||||
@ -348,14 +509,11 @@ $save_peer.on("click",function(){
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// QR Code
|
||||
let qrcodeModal = new bootstrap.Modal(document.getElementById('qrcode_modal'), {
|
||||
keyboard: false
|
||||
});
|
||||
// QR Code
|
||||
$body.on("click", ".btn-qrcode-peer", function (){
|
||||
|
||||
|
||||
let src = $(this).attr('img_src');
|
||||
$.ajax({
|
||||
"url": src,
|
||||
@ -606,7 +764,6 @@ function copyToClipboard(element) {
|
||||
|
||||
// Update Interval
|
||||
$body.on("click", ".update_interval", function(){
|
||||
let prev = $(".interval-btn-group.active button");
|
||||
$(".interval-btn-group button").removeClass("active");
|
||||
let _new = $(this);
|
||||
_new.addClass("active");
|
||||
@ -629,7 +786,7 @@ $body.on("click", ".update_interval", function(){
|
||||
showToast("Refresh Interval set unsuccessful");
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Refresh Button
|
||||
@ -681,7 +838,7 @@ $("#bulk_add").on("change", function (){
|
||||
}
|
||||
amount.attr("disabled", "disabled");
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Configuration sub menu
|
||||
let $setting_btn_menu = $(".setting_btn_menu");
|
||||
@ -692,23 +849,23 @@ $setting_btn.on("click", function(){
|
||||
$setting_btn_menu.removeClass("showing");
|
||||
setTimeout(function(){
|
||||
$setting_btn_menu.removeClass("show");
|
||||
}, 201)
|
||||
}, 201);
|
||||
|
||||
}else{
|
||||
$setting_btn_menu.addClass("show");
|
||||
setTimeout(function(){
|
||||
$setting_btn_menu.addClass("showing");
|
||||
},10)
|
||||
},10);
|
||||
}
|
||||
})
|
||||
$body.on("click", function(r){
|
||||
$("html").on("click", function(r){
|
||||
if (document.querySelector(".setting_btn") !== r.target){
|
||||
if (!document.querySelector(".setting_btn").contains(r.target)){
|
||||
if (!document.querySelector(".setting_btn_menu").contains(r.target)){
|
||||
$setting_btn_menu.removeClass("showing");
|
||||
setTimeout(function(){
|
||||
$setting_btn_menu.removeClass("show");
|
||||
}, 310)
|
||||
}, 310);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -794,12 +951,56 @@ $("#confirm_delete_bulk_peers").on("click", function(){
|
||||
|
||||
$("#select_all_delete_bulk_peers").on("click", function(){
|
||||
$(".delete-bulk-peer-item").each(function(){
|
||||
if (!$(this).hasClass("active")) toggleBulkIP($(this));
|
||||
if (!$(this).hasClass("active")) {
|
||||
toggleBulkIP($(this));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(deleteBulkModal._element).on("hidden.bs.modal", function(){
|
||||
$(".delete-bulk-peer-item").each(function(){
|
||||
if ($(this).hasClass("active")) toggleBulkIP($(this));
|
||||
if ($(this).hasClass("active")) {
|
||||
toggleBulkIP($(this));
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
// Download Peers
|
||||
function download_one_config(conf){
|
||||
let link = document.createElement('a');
|
||||
link.download = conf.filename;
|
||||
let blob = new Blob([conf.content], {type: 'text/conf'});
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.click();
|
||||
}
|
||||
|
||||
function download_all_config(confs){
|
||||
wireguard.generateZipFiles(confs);
|
||||
}
|
||||
|
||||
$body.on("click", ".btn-download-peer", function(e){
|
||||
e.preventDefault();
|
||||
let link = $(this).attr("href");
|
||||
$.ajax({
|
||||
"url": link,
|
||||
"method": "GET",
|
||||
success: function(res){
|
||||
download_one_config(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#download_all_peers").on("click", function(){
|
||||
$.ajax({
|
||||
"url": $(this).data("url"),
|
||||
"method": "GET",
|
||||
success: function(res){
|
||||
if (res.peers.length > 0){
|
||||
download_all_config(res);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
2
src/static/js/configuration.min.js
vendored
2
src/static/js/configuration.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,63 +1,67 @@
|
||||
$(".ip_dropdown").change(function (){
|
||||
$(".modal.show .btn").removeAttr("disabled")
|
||||
/**
|
||||
* tools.js - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]
|
||||
*/
|
||||
|
||||
$(".ip_dropdown").on("change",function (){
|
||||
$(".modal.show .btn").removeAttr("disabled");
|
||||
});
|
||||
$(".conf_dropdown").change(function (){
|
||||
$(".modal.show .ip_dropdown").html('<option value="none" selected="selected" disabled>Loading...')
|
||||
|
||||
$(".conf_dropdown").on("change", function (){
|
||||
$(".modal.show .ip_dropdown").html('<option value="none" selected="selected" disabled>Loading...');
|
||||
$.ajax({
|
||||
url: "/get_ping_ip",
|
||||
method: "POST",
|
||||
data: "config="+$(this).children("option:selected").val(),
|
||||
data: "config=" + $(this).children("option:selected").val(),
|
||||
success: function (res){
|
||||
$(".modal.show .ip_dropdown").html("")
|
||||
$(".modal.show .ip_dropdown").append('<option value="none" selected="selected" disabled>Choose an IP')
|
||||
$(".modal.show .ip_dropdown").append(res)
|
||||
$(".modal.show .ip_dropdown").html("");
|
||||
$(".modal.show .ip_dropdown").append('<option value="none" selected="selected" disabled>Choose an IP');
|
||||
$(".modal.show .ip_dropdown").append(res);
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
// Ping Tools
|
||||
$(".send_ping").click(function (){
|
||||
$(this).attr("disabled","disabled")
|
||||
$(this).html("Pinging...")
|
||||
$("#ping_modal .form-control").attr("disabled","disabled")
|
||||
$(".send_ping").on("click", function (){
|
||||
$(this).attr("disabled","disabled");
|
||||
$(this).html("Pinging...");
|
||||
$("#ping_modal .form-control").attr("disabled","disabled");
|
||||
$.ajax({
|
||||
method:"POST",
|
||||
data: "ip="+$(':selected', $("#ping_modal .ip_dropdown")).val()+"&count="+$("#ping_modal .ping_count").val(),
|
||||
data: "ip="+ $(':selected', $("#ping_modal .ip_dropdown")).val() +
|
||||
"&count=" + $("#ping_modal .ping_count").val(),
|
||||
url: "/ping_ip",
|
||||
success: function (res){
|
||||
$(".ping_result tbody").html("")
|
||||
html = '<tr><th scope="row">Address</th><td>'+res['address']+'</td></tr>' +
|
||||
'<tr><th scope="row">Is Alive</th><td>'+res['is_alive']+'</td></tr>' +
|
||||
'<tr><th scope="row">Min RTT</th><td>'+res['min_rtt']+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Average RTT </th><td>'+res['avg_rtt']+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Max RTT</th><td>'+res['max_rtt']+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Package Sent</th><td>'+res['package_sent']+'</td></tr>' +
|
||||
'<tr><th scope="row">Package Received</th><td>'+res['package_received']+'</td></tr>' +
|
||||
'<tr><th scope="row">Package Loss</th><td>'+res['package_loss']+'</td></tr>'
|
||||
$(".ping_result tbody").html(html)
|
||||
$(".send_ping").removeAttr("disabled")
|
||||
$(".send_ping").html("Ping")
|
||||
$("#ping_modal .form-control").removeAttr("disabled")
|
||||
$(".ping_result tbody").html("");
|
||||
let html = '<tr><th scope="row">Address</th><td>'+res.address+'</td></tr>' +
|
||||
'<tr><th scope="row">Is Alive</th><td>'+res.is_alive+'</td></tr>' +
|
||||
'<tr><th scope="row">Min RTT</th><td>'+res.min_rtt+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Average RTT </th><td>'+res.avg_rtt+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Max RTT</th><td>'+res.max_rtt+'ms</td></tr>' +
|
||||
'<tr><th scope="row">Package Sent</th><td>'+res.package_sent+'</td></tr>' +
|
||||
'<tr><th scope="row">Package Received</th><td>'+res.package_received+'</td></tr>' +
|
||||
'<tr><th scope="row">Package Loss</th><td>'+res.package_loss+'</td></tr>';
|
||||
$(".ping_result tbody").html(html);
|
||||
$(".send_ping").removeAttr("disabled");
|
||||
$(".send_ping").html("Ping");
|
||||
$("#ping_modal .form-control").removeAttr("disabled");
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Traceroute Tools
|
||||
$(".send_traceroute").click(function (){
|
||||
$(this).attr("disabled","disabled")
|
||||
$(".send_traceroute").on("click", function (){
|
||||
$(this).attr("disabled","disabled");
|
||||
$(this).html("Tracing...");
|
||||
$("#traceroute_modal .form-control").attr("disabled","disabled")
|
||||
$("#traceroute_modal .form-control").attr("disabled","disabled");
|
||||
$.ajax({
|
||||
url: "/traceroute_ip",
|
||||
method: "POST",
|
||||
data: "ip="+$(':selected', $("#traceroute_modal .ip_dropdown")).val(),
|
||||
data: "ip=" + $(':selected', $("#traceroute_modal .ip_dropdown")).val(),
|
||||
success: function (res){
|
||||
$(".traceroute_result tbody").html("");
|
||||
for (i in res){
|
||||
$(".traceroute_result tbody").append('<tr><th scope="row">'+res[i]['hop']+'</th><td>'+res[i]['ip']+'</td><td>'+res[i]['avg_rtt']+'</td><td>'+res[i]['min_rtt']+'</td><td>'+res[i]['max_rtt']+'</td></tr>')
|
||||
res.forEach((ele) =>
|
||||
$(".traceroute_result tbody").append('<tr><th scope="row">'+ele.hop+'</th><td>'+ele.ip+'</td><td>'+ele.avg_rtt+'</td><td>'+ele.min_rtt+'</td><td>'+ele.max_rtt+'</td></tr>'));
|
||||
$(".send_traceroute").removeAttr("disabled").html("Traceroute");
|
||||
$("#traceroute_modal .form-control").removeAttr("disabled");
|
||||
}
|
||||
$(".send_traceroute").removeAttr("disabled");
|
||||
$(".send_traceroute").html("Traceroute");
|
||||
$("#traceroute_modal .form-control").removeAttr("disabled")
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
2
src/static/js/tools.min.js
vendored
2
src/static/js/tools.min.js
vendored
@ -1 +1 @@
|
||||
$(".ip_dropdown").change(function(){$(".modal.show .btn").removeAttr("disabled")});$(".conf_dropdown").change(function(){$(".modal.show .ip_dropdown").html('<option value="none" selected="selected" disabled>Loading...');$.ajax({url:"/get_ping_ip",method:"POST",data:"config="+$(this).children("option:selected").val(),success:function(res){$(".modal.show .ip_dropdown").html("");$(".modal.show .ip_dropdown").append('<option value="none" selected="selected" disabled>Choose an IP');$(".modal.show .ip_dropdown").append(res)}})});$(".send_ping").click(function(){$(this).attr("disabled","disabled");$(this).html("Pinging...");$("#ping_modal .form-control").attr("disabled","disabled");$.ajax({method:"POST",data:"ip="+$(":selected",$("#ping_modal .ip_dropdown")).val()+"&count="+$("#ping_modal .ping_count").val(),url:"/ping_ip",success:function(res){$(".ping_result tbody").html("");html='<tr><th scope="row">Address</th><td>'+res["address"]+"</td></tr>"+'<tr><th scope="row">Is Alive</th><td>'+res["is_alive"]+"</td></tr>"+'<tr><th scope="row">Min RTT</th><td>'+res["min_rtt"]+"ms</td></tr>"+'<tr><th scope="row">Average RTT </th><td>'+res["avg_rtt"]+"ms</td></tr>"+'<tr><th scope="row">Max RTT</th><td>'+res["max_rtt"]+"ms</td></tr>"+'<tr><th scope="row">Package Sent</th><td>'+res["package_sent"]+"</td></tr>"+'<tr><th scope="row">Package Received</th><td>'+res["package_received"]+"</td></tr>"+'<tr><th scope="row">Package Loss</th><td>'+res["package_loss"]+"</td></tr>";$(".ping_result tbody").html(html);$(".send_ping").removeAttr("disabled");$(".send_ping").html("Ping");$("#ping_modal .form-control").removeAttr("disabled")}})});$(".send_traceroute").click(function(){$(this).attr("disabled","disabled");$(this).html("Tracing...");$("#traceroute_modal .form-control").attr("disabled","disabled");$.ajax({url:"/traceroute_ip",method:"POST",data:"ip="+$(":selected",$("#traceroute_modal .ip_dropdown")).val(),success:function(res){$(".traceroute_result tbody").html("");for(i in res){$(".traceroute_result tbody").append('<tr><th scope="row">'+res[i]["hop"]+"</th><td>"+res[i]["ip"]+"</td><td>"+res[i]["avg_rtt"]+"</td><td>"+res[i]["min_rtt"]+"</td><td>"+res[i]["max_rtt"]+"</td></tr>")}$(".send_traceroute").removeAttr("disabled");$(".send_traceroute").html("Traceroute");$("#traceroute_modal .form-control").removeAttr("disabled")}})});
|
||||
$(".ip_dropdown").on("change",function(){$(".modal.show .btn").removeAttr("disabled")});$(".conf_dropdown").on("change",function(){$(".modal.show .ip_dropdown").html('<option value="none" selected="selected" disabled>Loading...');$.ajax({url:"/get_ping_ip",method:"POST",data:"config="+$(this).children("option:selected").val(),success:function(res){$(".modal.show .ip_dropdown").html("");$(".modal.show .ip_dropdown").append('<option value="none" selected="selected" disabled>Choose an IP');$(".modal.show .ip_dropdown").append(res)}})});$(".send_ping").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Pinging...");$("#ping_modal .form-control").attr("disabled","disabled");$.ajax({method:"POST",data:"ip="+$(":selected",$("#ping_modal .ip_dropdown")).val()+"&count="+$("#ping_modal .ping_count").val(),url:"/ping_ip",success:function(res){$(".ping_result tbody").html("");let html='<tr><th scope="row">Address</th><td>'+res.address+"</td></tr>"+'<tr><th scope="row">Is Alive</th><td>'+res.is_alive+"</td></tr>"+'<tr><th scope="row">Min RTT</th><td>'+res.min_rtt+"ms</td></tr>"+'<tr><th scope="row">Average RTT </th><td>'+res.avg_rtt+"ms</td></tr>"+'<tr><th scope="row">Max RTT</th><td>'+res.max_rtt+"ms</td></tr>"+'<tr><th scope="row">Package Sent</th><td>'+res.package_sent+"</td></tr>"+'<tr><th scope="row">Package Received</th><td>'+res.package_received+"</td></tr>"+'<tr><th scope="row">Package Loss</th><td>'+res.package_loss+"</td></tr>";$(".ping_result tbody").html(html);$(".send_ping").removeAttr("disabled");$(".send_ping").html("Ping");$("#ping_modal .form-control").removeAttr("disabled")}})});$(".send_traceroute").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Tracing...");$("#traceroute_modal .form-control").attr("disabled","disabled");$.ajax({url:"/traceroute_ip",method:"POST",data:"ip="+$(":selected",$("#traceroute_modal .ip_dropdown")).val(),success:function(res){$(".traceroute_result tbody").html("");res.forEach(ele=>$(".traceroute_result tbody").append('<tr><th scope="row">'+ele.hop+"</th><td>"+ele.ip+"</td><td>"+ele.avg_rtt+"</td><td>"+ele.min_rtt+"</td><td>"+ele.max_rtt+"</td></tr>"));$(".send_traceroute").removeAttr("disabled").html("Traceroute");$("#traceroute_modal .form-control").removeAttr("disabled")}})});
|
@ -171,6 +171,105 @@
|
||||
return String.fromCharCode.apply(null, base64);
|
||||
}
|
||||
|
||||
function putU32(b, n)
|
||||
{
|
||||
b.push(n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff);
|
||||
}
|
||||
|
||||
function putU16(b, n)
|
||||
{
|
||||
b.push(n & 0xff, (n >>> 8) & 0xff);
|
||||
}
|
||||
|
||||
function putBytes(b, a)
|
||||
{
|
||||
for (var i = 0; i < a.length; ++i)
|
||||
b.push(a[i] & 0xff);
|
||||
}
|
||||
|
||||
function encodeString(s)
|
||||
{
|
||||
var utf8 = unescape(encodeURIComponent(s));
|
||||
var b = new Uint8Array(utf8.length);
|
||||
for (var i = 0; i < utf8.length; ++i)
|
||||
b[i] = utf8.charCodeAt(i);
|
||||
return b;
|
||||
}
|
||||
|
||||
function crc32(b)
|
||||
{
|
||||
if (!crc32.table) {
|
||||
crc32.table = [];
|
||||
for (var c = 0, n = 0; n < 256; c = ++n) {
|
||||
for (var k = 0; k < 8; ++k)
|
||||
c = ((c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1));
|
||||
crc32.table[n] = c;
|
||||
}
|
||||
}
|
||||
var crc = -1;
|
||||
for (var i = 0; i < b.length; ++i)
|
||||
crc = (crc >>> 8) ^ crc32.table[(crc ^ b[i]) & 0xff];
|
||||
return (crc ^ (-1)) >>> 0;
|
||||
}
|
||||
|
||||
function createZipFile(files)
|
||||
{
|
||||
var b = [];
|
||||
var cd = [];
|
||||
var offset = 0;
|
||||
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
var name = encodeString(files[i].filename);
|
||||
var contents = encodeString(files[i].content);
|
||||
var crc = crc32(contents);
|
||||
|
||||
putU32(b, 0x04034b50); /* signature */
|
||||
putU16(b, 20); /* version needed */
|
||||
putU16(b, 0); /* flags */
|
||||
putU16(b, 0); /* compression method */
|
||||
putU16(b, 0); /* mtime */
|
||||
putU16(b, 0); /* mdate */
|
||||
putU32(b, crc); /* crc32 */
|
||||
putU32(b, contents.length); /* compressed size */
|
||||
putU32(b, contents.length); /* uncompressed size */
|
||||
putU16(b, name.length); /* file name length */
|
||||
putU16(b, 0); /* extra field length */
|
||||
putBytes(b, name);
|
||||
putBytes(b, contents);
|
||||
|
||||
putU32(cd, 0x02014b50); /* signature */
|
||||
putU16(cd, 0); /* version made */
|
||||
putU16(cd, 20); /* version needed */
|
||||
putU16(cd, 0); /* flags */
|
||||
putU16(cd, 0); /* compression method */
|
||||
putU16(cd, 0); /* mtime */
|
||||
putU16(cd, 0); /* mdate */
|
||||
putU32(cd, crc); /* crc32 */
|
||||
putU32(cd, contents.length); /* compressed size */
|
||||
putU32(cd, contents.length); /* uncompressed size */
|
||||
putU16(cd, name.length); /* file name length */
|
||||
putU16(cd, 0); /* extra field length */
|
||||
putU16(cd, 0); /* file comment length */
|
||||
putU16(cd, 0); /* disk number start */
|
||||
putU16(cd, 0); /* internal file attributes */
|
||||
putU32(cd, 32); /* external file attributes - 'archive' bit set (32) */
|
||||
putU32(cd, offset); /* relative offset of local header */
|
||||
putBytes(cd, name); /* file name */
|
||||
|
||||
offset += 30 + contents.length + name.length
|
||||
}
|
||||
putBytes(b, cd); /* central directory */
|
||||
putU32(b, 0x06054b50); /* end of central directory signature */
|
||||
putU16(b, 0); /* number of this disk */
|
||||
putU16(b, 0); /* number of disk with central directory start */
|
||||
putU16(b, files.length); /* number of entries on disk */
|
||||
putU16(b, files.length); /* number of entries */
|
||||
putU32(b, cd.length); /* length of central directory */
|
||||
putU32(b, offset); /* offset to start of central directory */
|
||||
putU16(b, 0); /* zip comment size */
|
||||
return Uint8Array.from(b);
|
||||
}
|
||||
|
||||
window.wireguard = {
|
||||
generateKeypair: function() {
|
||||
var privateKey = generatePrivateKey();
|
||||
@ -184,6 +283,19 @@
|
||||
},
|
||||
generatePublicKey: function (privateKey){
|
||||
return keyToBase64(generatePublicKey(privateKey))
|
||||
},
|
||||
|
||||
generateZipFiles: function(res){
|
||||
var files = res.peers;
|
||||
var zipFile = createZipFile(files);
|
||||
var blob = new Blob([zipFile], { type: "application/zip" });
|
||||
var a = document.createElement("a");
|
||||
a.download = res.filename;
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.style.display = "none";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
2
src/static/js/wireguard.min.js
vendored
2
src/static/js/wireguard.min.js
vendored
@ -1 +1 @@
|
||||
(function(){function gf(init){var r=new Float64Array(16);if(init){for(var i=0;i<init.length;++i)r[i]=init[i]}return r}function pack(o,n){var b,m=gf(),t=gf();for(var i=0;i<16;++i)t[i]=n[i];carry(t);carry(t);carry(t);for(var j=0;j<2;++j){m[0]=t[0]-65517;for(var i=1;i<15;++i){m[i]=t[i]-65535-(m[i-1]>>16&1);m[i-1]&=65535}m[15]=t[15]-32767-(m[14]>>16&1);b=m[15]>>16&1;m[14]&=65535;cswap(t,m,1-b)}for(var i=0;i<16;++i){o[2*i]=t[i]&255;o[2*i+1]=t[i]>>8}}function carry(o){var c;for(var i=0;i<16;++i){o[(i+1)%16]+=(i<15?1:38)*Math.floor(o[i]/65536);o[i]&=65535}}function cswap(p,q,b){var t,c=~(b-1);for(var i=0;i<16;++i){t=c&(p[i]^q[i]);p[i]^=t;q[i]^=t}}function add(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]+b[i]|0}function subtract(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]-b[i]|0}function multmod(o,a,b){var t=new Float64Array(31);for(var i=0;i<16;++i){for(var j=0;j<16;++j)t[i+j]+=a[i]*b[j]}for(var i=0;i<15;++i)t[i]+=38*t[i+16];for(var i=0;i<16;++i)o[i]=t[i];carry(o);carry(o)}function invert(o,i){var c=gf();for(var a=0;a<16;++a)c[a]=i[a];for(var a=253;a>=0;--a){multmod(c,c,c);if(a!==2&&a!==4)multmod(c,c,i)}for(var a=0;a<16;++a)o[a]=c[a]}function clamp(z){z[31]=z[31]&127|64;z[0]&=248}function generatePublicKey(privateKey){var r,z=new Uint8Array(32);var a=gf([1]),b=gf([9]),c=gf(),d=gf([1]),e=gf(),f=gf(),_121665=gf([56129,1]),_9=gf([9]);for(var i=0;i<32;++i)z[i]=privateKey[i];clamp(z);for(var i=254;i>=0;--i){r=z[i>>>3]>>>(i&7)&1;cswap(a,b,r);cswap(c,d,r);add(e,a,c);subtract(a,a,c);add(c,b,d);subtract(b,b,d);multmod(d,e,e);multmod(f,a,a);multmod(a,c,a);multmod(c,b,e);add(e,a,c);subtract(a,a,c);multmod(b,a,a);subtract(c,d,f);multmod(a,c,_121665);add(a,a,d);multmod(c,c,a);multmod(a,d,f);multmod(d,b,_9);multmod(b,e,e);cswap(a,b,r);cswap(c,d,r)}invert(c,c);multmod(a,a,c);pack(z,a);return z}function generatePresharedKey(){var privateKey=new Uint8Array(32);window.crypto.getRandomValues(privateKey);return privateKey}function generatePrivateKey(){var privateKey=generatePresharedKey();clamp(privateKey);return privateKey}function encodeBase64(dest,src){var input=Uint8Array.from([src[0]>>2&63,(src[0]<<4|src[1]>>4)&63,(src[1]<<2|src[2]>>6)&63,src[2]&63]);for(var i=0;i<4;++i)dest[i]=input[i]+65+(25-input[i]>>8&6)-(51-input[i]>>8&75)-(61-input[i]>>8&15)+(62-input[i]>>8&3)}function keyToBase64(key){var i,base64=new Uint8Array(44);for(i=0;i<32/3;++i)encodeBase64(base64.subarray(i*4),key.subarray(i*3));encodeBase64(base64.subarray(i*4),Uint8Array.from([key[i*3+0],key[i*3+1],0]));base64[43]=61;return String.fromCharCode.apply(null,base64)}window.wireguard={generateKeypair:function(){var privateKey=generatePrivateKey();var publicKey=generatePublicKey(privateKey);var presharedKey=generatePresharedKey();return{publicKey:keyToBase64(publicKey),privateKey:keyToBase64(privateKey),presharedKey:keyToBase64(presharedKey)}},generatePublicKey:function(privateKey){return keyToBase64(generatePublicKey(privateKey))}}})();
|
||||
(function(){function gf(init){var r=new Float64Array(16);if(init){for(var i=0;i<init.length;++i)r[i]=init[i]}return r}function pack(o,n){var b,m=gf(),t=gf();for(var i=0;i<16;++i)t[i]=n[i];carry(t);carry(t);carry(t);for(var j=0;j<2;++j){m[0]=t[0]-65517;for(var i=1;i<15;++i){m[i]=t[i]-65535-(m[i-1]>>16&1);m[i-1]&=65535}m[15]=t[15]-32767-(m[14]>>16&1);b=m[15]>>16&1;m[14]&=65535;cswap(t,m,1-b)}for(var i=0;i<16;++i){o[2*i]=t[i]&255;o[2*i+1]=t[i]>>8}}function carry(o){var c;for(var i=0;i<16;++i){o[(i+1)%16]+=(i<15?1:38)*Math.floor(o[i]/65536);o[i]&=65535}}function cswap(p,q,b){var t,c=~(b-1);for(var i=0;i<16;++i){t=c&(p[i]^q[i]);p[i]^=t;q[i]^=t}}function add(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]+b[i]|0}function subtract(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]-b[i]|0}function multmod(o,a,b){var t=new Float64Array(31);for(var i=0;i<16;++i){for(var j=0;j<16;++j)t[i+j]+=a[i]*b[j]}for(var i=0;i<15;++i)t[i]+=38*t[i+16];for(var i=0;i<16;++i)o[i]=t[i];carry(o);carry(o)}function invert(o,i){var c=gf();for(var a=0;a<16;++a)c[a]=i[a];for(var a=253;a>=0;--a){multmod(c,c,c);if(a!==2&&a!==4)multmod(c,c,i)}for(var a=0;a<16;++a)o[a]=c[a]}function clamp(z){z[31]=z[31]&127|64;z[0]&=248}function generatePublicKey(privateKey){var r,z=new Uint8Array(32);var a=gf([1]),b=gf([9]),c=gf(),d=gf([1]),e=gf(),f=gf(),_121665=gf([56129,1]),_9=gf([9]);for(var i=0;i<32;++i)z[i]=privateKey[i];clamp(z);for(var i=254;i>=0;--i){r=z[i>>>3]>>>(i&7)&1;cswap(a,b,r);cswap(c,d,r);add(e,a,c);subtract(a,a,c);add(c,b,d);subtract(b,b,d);multmod(d,e,e);multmod(f,a,a);multmod(a,c,a);multmod(c,b,e);add(e,a,c);subtract(a,a,c);multmod(b,a,a);subtract(c,d,f);multmod(a,c,_121665);add(a,a,d);multmod(c,c,a);multmod(a,d,f);multmod(d,b,_9);multmod(b,e,e);cswap(a,b,r);cswap(c,d,r)}invert(c,c);multmod(a,a,c);pack(z,a);return z}function generatePresharedKey(){var privateKey=new Uint8Array(32);window.crypto.getRandomValues(privateKey);return privateKey}function generatePrivateKey(){var privateKey=generatePresharedKey();clamp(privateKey);return privateKey}function encodeBase64(dest,src){var input=Uint8Array.from([src[0]>>2&63,(src[0]<<4|src[1]>>4)&63,(src[1]<<2|src[2]>>6)&63,src[2]&63]);for(var i=0;i<4;++i)dest[i]=input[i]+65+(25-input[i]>>8&6)-(51-input[i]>>8&75)-(61-input[i]>>8&15)+(62-input[i]>>8&3)}function keyToBase64(key){var i,base64=new Uint8Array(44);for(i=0;i<32/3;++i)encodeBase64(base64.subarray(i*4),key.subarray(i*3));encodeBase64(base64.subarray(i*4),Uint8Array.from([key[i*3+0],key[i*3+1],0]));base64[43]=61;return String.fromCharCode.apply(null,base64)}function putU32(b,n){b.push(n&255,n>>>8&255,n>>>16&255,n>>>24&255)}function putU16(b,n){b.push(n&255,n>>>8&255)}function putBytes(b,a){for(var i=0;i<a.length;++i)b.push(a[i]&255)}function encodeString(s){var utf8=unescape(encodeURIComponent(s));var b=new Uint8Array(utf8.length);for(var i=0;i<utf8.length;++i)b[i]=utf8.charCodeAt(i);return b}function crc32(b){if(!crc32.table){crc32.table=[];for(var c=0,n=0;n<256;c=++n){for(var k=0;k<8;++k)c=c&1?3988292384^c>>>1:c>>>1;crc32.table[n]=c}}var crc=-1;for(var i=0;i<b.length;++i)crc=crc>>>8^crc32.table[(crc^b[i])&255];return(crc^-1)>>>0}function createZipFile(files){var b=[];var cd=[];var offset=0;for(var i=0;i<files.length;++i){var name=encodeString(files[i].filename);var contents=encodeString(files[i].content);var crc=crc32(contents);putU32(b,67324752);putU16(b,20);putU16(b,0);putU16(b,0);putU16(b,0);putU16(b,0);putU32(b,crc);putU32(b,contents.length);putU32(b,contents.length);putU16(b,name.length);putU16(b,0);putBytes(b,name);putBytes(b,contents);putU32(cd,33639248);putU16(cd,0);putU16(cd,20);putU16(cd,0);putU16(cd,0);putU16(cd,0);putU16(cd,0);putU32(cd,crc);putU32(cd,contents.length);putU32(cd,contents.length);putU16(cd,name.length);putU16(cd,0);putU16(cd,0);putU16(cd,0);putU16(cd,0);putU32(cd,32);putU32(cd,offset);putBytes(cd,name);offset+=30+contents.length+name.length}putBytes(b,cd);putU32(b,101010256);putU16(b,0);putU16(b,0);putU16(b,files.length);putU16(b,files.length);putU32(b,cd.length);putU32(b,offset);putU16(b,0);return Uint8Array.from(b)}window.wireguard={generateKeypair:function(){var privateKey=generatePrivateKey();var publicKey=generatePublicKey(privateKey);var presharedKey=generatePresharedKey();return{publicKey:keyToBase64(publicKey),privateKey:keyToBase64(privateKey),presharedKey:keyToBase64(presharedKey)}},generatePublicKey:function(privateKey){return keyToBase64(generatePublicKey(privateKey))},generateZipFiles:function(res){var files=res.peers;var zipFile=createZipFile(files);var blob=new Blob([zipFile],{type:"application/zip"});var a=document.createElement("a");a.download=res.filename;a.href=URL.createObjectURL(blob);a.style.display="none";document.body.appendChild(a);a.click();document.body.removeChild(a)}}})();
|
@ -1,10 +1,18 @@
|
||||
<!-- configuration.html - < WGDashboard > - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]-->
|
||||
<html lang="en">
|
||||
{% with title=title%}
|
||||
{% include "header.html"%}
|
||||
{% endwith %}
|
||||
<body>
|
||||
<div class="no-response">
|
||||
<div class="container">
|
||||
<h1 class="text-white display-1"><i class="bi bi-emoji-frown-fill"></i></h1>
|
||||
<h4 class="text-white">Oops!<br>I can't connect to the server.</h4>
|
||||
</div>
|
||||
</div>
|
||||
{% include "navbar.html" %}
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="container-fluid" id="right_body">
|
||||
{% include "sidebar.html" %}
|
||||
<div class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4 mb-4">
|
||||
<div class="form-group">
|
||||
@ -105,7 +113,7 @@
|
||||
<button type="button" class="btn btn-secondary setting_btn"><i class="bi bi-three-dots"></i></button>
|
||||
<div class="setting_btn_menu">
|
||||
<a class="text-danger" id="delete_peers_by_bulk_btn"><i class="bi bi-trash-fill"></i> Delete Peers</a>
|
||||
<a class="text-info"><i class="bi bi-cloud-download-fill"></i> Download All Peers</a>
|
||||
<a class="text-info" id="download_all_peers" data-url="/download_all/{{conf_data['name']}}"><i class="bi bi-cloud-download-fill"></i> Download All Peers</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -134,8 +142,8 @@
|
||||
<i class="bi bi-question-circle-fill" style="cursor: pointer" data-container="body" data-toggle="popover" data-placement="right" data-trigger="click" data-content="By adding peers by bulk, each peer's name will be auto generated, and Allowed IP will be assign to the next available IP."></i>
|
||||
</div>
|
||||
<div class="form-group" style="margin: 0">
|
||||
{# <label for="new_add_amount">Amount</label>#}
|
||||
<input type="number" class="form-control" id="new_add_amount" min="1" placeholder="Amount" disabled>
|
||||
<div id="bulk_amount_validation" class="invalid-feedback"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -406,122 +414,14 @@
|
||||
{% include "footer.html" %}
|
||||
<script src="{{ url_for('static',filename='js/wireguard.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/configuration.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
let load_timeout;
|
||||
let load_interval = 0;
|
||||
let conf_name = "{{ conf_data['name'] }}"
|
||||
let peers = [];
|
||||
$(".sb-"+conf_name+"-url").addClass("active");
|
||||
function load_data(search){
|
||||
startProgressBar()
|
||||
let result = '';
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/get_config/"+conf_name+"?search="+encodeURIComponent(search),
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
success: function (response){
|
||||
peers = response["peer_data"];
|
||||
{# Check all status #}
|
||||
if (response["listen_port"] === "" && response["status"] === "stopped"){
|
||||
$("config_info_alert").append('<div class="alert alert-warning" role="alert">Peer QR Code and configuration file download required a specified <strong>Listen Port</strong>.</div>')
|
||||
}
|
||||
if (response["conf_address"] === "N/A"){
|
||||
$("config_info_alert").append('<div class="alert alert-warning" role="alert">Configuration <strong>Address</strong> need to be specified to have peers connect to it.</div>')
|
||||
}
|
||||
{# Status Button #}
|
||||
if (response["checked"] === "checked"){
|
||||
$("#conf_status_btn").html('<a href="#" id="'+response["name"]+'" '+response["checked"]+' class="switch text-primary"><i class="bi bi-toggle2-on"></i> ON</a>');
|
||||
}else{
|
||||
$("#conf_status_btn").html('<a href="#" id="'+response["name"]+'" '+response["checked"]+' class="switch text-primary"><i class="bi bi-toggle2-off"></i> OFF</a>');
|
||||
}
|
||||
$("#sort_by_dropdown option").removeAttr("selected");
|
||||
$("#sort_by_dropdown option[value="+response["sort_tag"]+"]").attr("selected", "selected");
|
||||
$(".interval-btn-group button").removeClass("active");
|
||||
$("button[data-refresh-interval="+response["dashboard_refresh_interval"]+"]").addClass("active");
|
||||
$(".display-btn-group button").removeClass("active");
|
||||
$("button[data-display-mode="+response["peer_display_mode"]+"]").addClass("active");
|
||||
|
||||
|
||||
|
||||
$("#conf_status").html(response["status"]+'<span class="dot dot-'+response["status"]+'"></span>');
|
||||
$("#conf_connected_peers").html(response["running_peer"]);
|
||||
$("#conf_total_data_usage").html(response["total_data_usage"][0] +" GB");
|
||||
$("#conf_total_data_received").html(response["total_data_usage"][2] +" GB");
|
||||
$("#conf_total_data_sent").html(response["total_data_usage"][1]+" GB");
|
||||
$("#conf_public_key").html(response["public_key"]);
|
||||
$("#conf_listen_port").html(response["listen_port"] === "" ? "N/A":response["listen_port"]);
|
||||
$("#conf_address").html(response["conf_address"]);
|
||||
$(".info h6").removeClass("info_loading");
|
||||
$("#conf_status_btn").removeClass("info_loading")
|
||||
|
||||
|
||||
|
||||
if (response["peer_data"].length === 0){
|
||||
$(".peer_list").html('<div class="col-12" style="text-align: center; margin-top: 1.5rem"><h3 class="text-muted">Oops! No peers found ‘︿’</h3></div>');
|
||||
}else{
|
||||
let display_mode = response["peer_display_mode"] === "list" ? "col-12" : "col-sm-6 col-lg-4";
|
||||
response["peer_data"].forEach(function(peer){
|
||||
let total_r = 0;
|
||||
let total_s = 0;
|
||||
total_r += peer["cumu_receive"];
|
||||
total_s += peer["cumu_sent"];
|
||||
let spliter = '<div class="w-100"></div>';
|
||||
let peer_name =
|
||||
'<div class="col-sm display" style="display: flex; align-items: center; margin-bottom: 0.2rem">' +
|
||||
'<h5 style="margin: 0;">'+ (peer["name"] === "" ? "Untitled" : peer["name"]) +'</h5>' +
|
||||
'<h6 style="text-transform: uppercase; margin: 0; margin-left: auto !important;"><span class="dot dot-'+peer["status"]+'" style="margin-left: auto !important;" data-toggle="tooltip" data-placement="left" title="Peer Running"></span></h6>' +
|
||||
'</div>';
|
||||
let peer_transfer = '<div class="col-12 peer_data_group" style="text-align: right; display: flex; margin-bottom: 0.5rem"><p class="text-primary" style="text-transform: uppercase; margin-bottom: 0; margin-right: 1rem"><small><i class="bi bi-arrow-down-right"></i> '+ roundN(peer["total_receive"] + total_r, 4) +' GB</small></p> <p class="text-success" style="text-transform: uppercase; margin-bottom: 0"><small><i class="bi bi-arrow-up-right"></i> '+ roundN(peer["total_sent"] + total_s, 4) +' GB</small></p> </div>'
|
||||
let peer_key = '<div class="col-sm"><small class="text-muted" style="display: flex"><strong>PEER</strong><strong style="margin-left: auto!important; opacity: 0; transition: 0.2s ease-in-out" class="text-primary">CLICK TO COPY</strong></small> <h6><samp class="ml-auto key">'+peer["id"]+'</samp></h6></div>';
|
||||
let peer_allowed_ip = '<div class="col-sm"><small class="text-muted"><strong>ALLOWED IP</strong></small><h6 style="text-transform: uppercase;">'+peer["allowed_ip"]+'</h6></div>';
|
||||
let peer_latest_handshake = '<div class="col-sm"> <small class="text-muted"><strong>LATEST HANDSHAKE</strong></small> <h6 style="text-transform: uppercase;">'+peer['latest_handshake']+'</h6> </div>';
|
||||
let peer_endpoint = '<div class="col-sm"><small class="text-muted"><strong>END POINT</strong></small><h6 style="text-transform: uppercase;">'+peer["endpoint"]+'</h6></div>';
|
||||
let peer_control = '<div class="col-sm"><hr><div class="button-group" style="display:flex"><button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" id="'+peer["id"]+'" data-toggle="modal"><i class="bi bi-gear-fill" data-toggle="tooltip" data-placement="bottom" title="Peer Settings"></i></button> <button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="'+peer["id"]+'" data-toggle="modal"><i class="bi bi-x-circle-fill" data-toggle="tooltip" data-placement="bottom" title="Delete Peer"></i></button>';
|
||||
if (peer["private_key"] !== ""){
|
||||
peer_control += '<div class="share_peer_btn_group" style="margin-left: auto !important; display: inline"><button type="button" class="btn btn-outline-success btn-qrcode-peer btn-control" img_src="/qrcode/'+response['name']+'?id='+encodeURIComponent(peer["id"])+'"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 19px;" fill="#28a745"><path d="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zM13 3v8h8V3h-8zm6 6h-4V5h4v4zM13 13h2v2h-2zM15 15h2v2h-2zM13 17h2v2h-2zM17 17h2v2h-2zM19 19h2v2h-2zM15 19h2v2h-2zM17 13h2v2h-2zM19 15h2v2h-2z"/></svg></button><a href="/download/'+response["name"]+'?id='+encodeURIComponent(peer["id"])+'" class="btn btn-outline-info btn-download-peer btn-control"><i class="bi bi-download"></i></a></div>';
|
||||
}
|
||||
peer_control += '</div>';
|
||||
let html = '<div class="'+display_mode+'" data-id="'+peer["id"]+'">' +
|
||||
'<div class="card mb-3 card-'+peer["status"]+'">' +
|
||||
'<div class="card-body">' +
|
||||
'<div class="row">'
|
||||
+ peer_name
|
||||
+ spliter
|
||||
+ peer_transfer
|
||||
+ peer_key
|
||||
+ peer_allowed_ip
|
||||
+ peer_latest_handshake
|
||||
+ spliter
|
||||
+ peer_endpoint
|
||||
+ spliter
|
||||
+ peer_control
|
||||
+ '</div>' +
|
||||
'</div></div>' +
|
||||
'</div></div>';
|
||||
result += html;
|
||||
})
|
||||
$(".peer_list").html(result);
|
||||
if (response["dashboard_refresh_interval"] !== load_interval){
|
||||
load_interval = response["dashboard_refresh_interval"];
|
||||
clearInterval(load_timeout);
|
||||
load_timeout = setInterval(function (){
|
||||
load_data($('#search_peer_textbox').val());
|
||||
},response["dashboard_refresh_interval"])
|
||||
}
|
||||
}
|
||||
$(".dot.dot-running").attr("title","Peer Running").tooltip();
|
||||
$(".dot.dot-stopped").attr("title","Peer Stopped").tooltip();
|
||||
$("i[data-toggle='tooltip']").tooltip();
|
||||
endProgressBar()
|
||||
}
|
||||
})
|
||||
}
|
||||
$(function(){
|
||||
load_data($('#search_peer_textbox').val());
|
||||
});
|
||||
</script>
|
||||
|
||||
</html>
|
@ -1,4 +1,5 @@
|
||||
<html>
|
||||
<!-- index.html - < WGDashboard > - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]-->
|
||||
<html lang="en">
|
||||
{% with %}
|
||||
{% set title="Home" %}
|
||||
{% include "header.html"%}
|
||||
@ -9,7 +10,11 @@
|
||||
<div class="container-fluid">
|
||||
{% include "sidebar.html" %}
|
||||
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mb-4">
|
||||
<div style="display: flex; flex-direction: row; align-items: center;">
|
||||
<h1 class="pb-4 mt-4">Home</h1>
|
||||
{# <button class="btn btn-primary" style="margin-left: auto"><i class="bi bi-plus-circle-fill"></i> Configuration</button>#}
|
||||
</div>
|
||||
|
||||
{% 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 %}
|
||||
@ -20,7 +25,7 @@
|
||||
<div class="col card-col">
|
||||
<small class="text-muted"><strong>CONFIGURATION</strong></small>
|
||||
<a href="/configuration/{{i['conf']}}" class="conf_link">
|
||||
<h6 class="card-title" style="margin:0 !important;">{{i['conf']}}</h6>
|
||||
<h6 class="card-title" style="margin:0 !important;"><samp>{{i['conf']}}</samp></h6>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col card-col">
|
||||
|
@ -3,7 +3,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>WGDashboard | Login</title>
|
||||
<link rel="icon" href="{{ url_for('static',filename='logo.png') }}"/>
|
||||
<link rel="icon" href="{{ url_for('static',filename='img/logo.png') }}"/>
|
||||
<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='css/dashboard.css') }}">
|
||||
</head>
|
||||
@ -37,7 +37,7 @@
|
||||
</body>
|
||||
{% include "footer.html" %}
|
||||
<script>
|
||||
$("button").click(function(){
|
||||
$("button").on("click", function(){
|
||||
$(this).html("Signing In...")
|
||||
})
|
||||
</script>
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# wgd.sh - Copyright(C) 2021 Donald Zou [https://github.com/donaldzou]
|
||||
# Under Apache-2.0 License
|
||||
app_name="dashboard.py"
|
||||
app_official_name="WGDashboard"
|
||||
dashes='------------------------------------------------------------'
|
||||
|
Loading…
Reference in New Issue
Block a user