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

Successfully migrate to SQlite

This commit is contained in:
Donald Cheng Hong Zou 2022-01-02 14:44:27 -05:00
parent 06dd641274
commit 4f93d48ac6
4 changed files with 174 additions and 379 deletions

2
.gitignore vendored
View File

@ -15,3 +15,5 @@ public_key.txt
venv/** venv/**
log/** log/**
release/* release/*
*.db
src/db/wgdashboard.db

View File

@ -2,7 +2,9 @@
< WGDashboard > - by Donald Zou [https://github.com/donaldzou] < WGDashboard > - by Donald Zou [https://github.com/donaldzou]
Under Apache-2.0 License Under Apache-2.0 License
""" """
# TODO: Testing migrate to sqlite
import sqlite3
from flask import g
import configparser import configparser
import hashlib import hashlib
import ipaddress import ipaddress
@ -18,7 +20,7 @@ import urllib.parse
import urllib.request import urllib.request
from datetime import datetime, timedelta from datetime import datetime, timedelta
from operator import itemgetter from operator import itemgetter
import signal
# PIP installed library # PIP installed library
import ifcfg import ifcfg
from flask import Flask, request, render_template, redirect, url_for, session, jsonify from flask import Flask, request, render_template, redirect, url_for, session, jsonify
@ -27,7 +29,7 @@ from icmplib import ping, traceroute
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
# Import other python files # Import other python files
from util import regex_match, check_DNS, check_Allowed_IPs, check_remote_endpoint,\ from util import regex_match, check_DNS, check_Allowed_IPs, check_remote_endpoint, \
check_IP_with_range, clean_IP_with_range check_IP_with_range, clean_IP_with_range
# Dashboard Version # Dashboard Version
@ -48,8 +50,9 @@ app.config['TEMPLATES_AUTO_RELOAD'] = True
# Enable QR Code Generator # Enable QR Code Generator
QRcode(app) QRcode(app)
# TODO: Testing semaphore on reading/writing database
sem = threading.RLock() def connect_db():
return sqlite3.connect(os.path.join(configuration_path, 'db', 'wgdashboard.db'))
# Read / Write Dashboard Config File # Read / Write Dashboard Config File
@ -158,8 +161,8 @@ def read_conf_file(config_name):
return conf_peer_data return conf_peer_data
# Get latest handshake from all peers of a configuration # Get the latest handshake from all peers of a configuration
def get_latest_handshake(config_name, db, peers): def get_latest_handshake(config_name):
# Get latest handshakes # Get latest handshakes
try: try:
data_usage = subprocess.run(f"wg show {config_name} latest-handshakes", data_usage = subprocess.run(f"wg show {config_name} latest-handshakes",
@ -177,17 +180,17 @@ def get_latest_handshake(config_name, db, peers):
else: else:
status = "stopped" status = "stopped"
if int(data_usage[count + 1]) > 0: if int(data_usage[count + 1]) > 0:
db.update({"latest_handshake": str(minus).split(".", maxsplit=1)[0], "status": status}, g.cur.execute("UPDATE %s SET latest_handshake = '%s', status = '%s' WHERE id='%s'"
peers.id == data_usage[count]) % (config_name, str(minus).split(".", maxsplit=1)[0], status, data_usage[count]))
else: else:
db.update({"latest_handshake": "(None)", "status": status}, peers.id == data_usage[count]) g.cur.execute("UPDATE %s SET latest_handshake = '(None)', status = '%s' WHERE id='%s'"
% (config_name, status, data_usage[count]))
count += 2 count += 2
return None return None
# Get transfer from all peers of a configuration # Get transfer from all peers of a configuration
def get_transfer(config_name, db, peers): def get_transfer(config_name):
# Get transfer # Get transfer
try: try:
data_usage = subprocess.run(f"wg show {config_name} transfer", data_usage = subprocess.run(f"wg show {config_name} transfer",
@ -200,37 +203,37 @@ def get_transfer(config_name, db, peers):
final.append(i.split("\t")) final.append(i.split("\t"))
data_usage = final data_usage = final
for i in range(len(data_usage)): for i in range(len(data_usage)):
cur_i = db.search(peers.id == data_usage[i][0]) cur_i = g.cur.execute(
"SELECT total_receive, total_sent, cumu_receive, cumu_sent, status FROM %s WHERE id='%s'"
% (config_name, data_usage[i][0])).fetchall()
if len(cur_i) > 0: if len(cur_i) > 0:
total_sent = cur_i[0]['total_sent'] total_sent = cur_i[0][1]
total_receive = cur_i[0]['total_receive'] total_receive = cur_i[0][0]
traffic = cur_i[0]['traffic'] # traffic = cur_i[0]['traffic']
cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4) cur_total_sent = round(int(data_usage[i][2]) / (1024 ** 3), 4)
cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4) cur_total_receive = round(int(data_usage[i][1]) / (1024 ** 3), 4)
if cur_i[0]["status"] == "running": if cur_i[0][4] == "running":
if total_sent <= cur_total_sent and total_receive <= cur_total_receive: if total_sent <= cur_total_sent and total_receive <= cur_total_receive:
total_sent = cur_total_sent total_sent = cur_total_sent
total_receive = cur_total_receive total_receive = cur_total_receive
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( cumu_receive = cur_i[0][2] + total_receive
{ cumu_sent = cur_i[0][3] + total_sent
"time": ctime, "total_receive": round(total_receive, 4), g.cur.execute("UPDATE %s SET cumu_receive = %f, cumu_sent = %f, cumu_data = %f WHERE id = '%s'" %
"total_sent": round(total_sent, 4), (config_name, round(cumu_receive, 4), round(cumu_sent, 4),
"total_data": round(total_receive + total_sent, 4) round(cumu_sent + cumu_receive, 4), data_usage[i][0]))
}
)
total_sent = 0 total_sent = 0
total_receive = 0 total_receive = 0
db.update({"traffic": traffic}, peers.id == data_usage[i][0]) g.cur.execute("UPDATE %s SET total_receive = %f, total_sent = %f, total_data = %f WHERE id = '%s'" %
db.update({"total_receive": round(total_receive, 4), "total_sent": round(total_sent, 4), (config_name, round(total_receive, 4), round(total_sent, 4),
"total_data": round(total_receive + total_sent, 4)}, peers.id == data_usage[i][0]) round(total_receive + total_sent, 4), data_usage[i][0]))
return None return None
# Get endpoint from all peers of a configuration # Get endpoint from all peers of a configuration
def get_endpoint(config_name, db, peers): def get_endpoint(config_name):
# Get endpoint # Get endpoint
try: try:
data_usage = subprocess.run(f"wg show {config_name} endpoints", data_usage = subprocess.run(f"wg show {config_name} endpoints",
@ -240,29 +243,27 @@ def get_endpoint(config_name, db, peers):
data_usage = data_usage.decode("UTF-8").split() data_usage = data_usage.decode("UTF-8").split()
count = 0 count = 0
for _ in range(int(len(data_usage) / 2)): for _ in range(int(len(data_usage) / 2)):
db.update({"endpoint": data_usage[count + 1]}, peers.id == data_usage[count]) g.cur.execute("UPDATE " + config_name + " SET endpoint = '%s' WHERE id = '%s'"
% (data_usage[count + 1], data_usage[count]))
count += 2 count += 2
return None return None
# Get allowed ips from all peers of a configuration # Get allowed ips from all peers of a configuration
def get_allowed_ip(db, peers, conf_peer_data): def get_allowed_ip(conf_peer_data, config_name):
# 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"]) g.cur.execute("UPDATE " + config_name + " SET allowed_ip = '%s' WHERE id = '%s'"
% (i.get('AllowedIPs', '(None)'), i["PublicKey"]))
# Look for new peers from WireGuard # Look for new peers from WireGuard
def get_all_peers_data(config_name): def get_all_peers_data(config_name):
sem.acquire(timeout=1)
db = TinyDB(os.path.join(db_path, config_name + '.json'))
peers = Query()
conf_peer_data = read_conf_file(config_name) conf_peer_data = read_conf_file(config_name)
config = get_dashboard_conf() config = get_dashboard_conf()
for i in conf_peer_data['Peers']: for i in conf_peer_data['Peers']:
search = db.search(peers.id == i['PublicKey']) result = g.cur.execute("SELECT * FROM %s WHERE id='%s'" % (config_name, i["PublicKey"])).fetchall()
if not search: if len(result) == 0:
new_data = { new_data = {
"id": i['PublicKey'], "id": i['PublicKey'],
"private_key": "", "private_key": "",
@ -276,6 +277,9 @@ def get_all_peers_data(config_name):
"status": "stopped", "status": "stopped",
"latest_handshake": "N/A", "latest_handshake": "N/A",
"allowed_ip": "N/A", "allowed_ip": "N/A",
"cumu_receive": 0,
"cumu_sent": 0,
"cumu_data": 0,
"traffic": [], "traffic": [],
"mtu": config.get("Peers", "peer_mtu"), "mtu": config.get("Peers", "peer_mtu"),
"keepalive": config.get("Peers", "peer_keep_alive"), "keepalive": config.get("Peers", "peer_keep_alive"),
@ -284,48 +288,25 @@ def get_all_peers_data(config_name):
} }
if "PresharedKey" in i.keys(): if "PresharedKey" in i.keys():
new_data["preshared_key"] = i["PresharedKey"] new_data["preshared_key"] = i["PresharedKey"]
db.insert(new_data) 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)
else: else:
# Update database since V2.2 pass
update_db = {}
# Required peer settings
if "DNS" not in search[0]:
update_db['DNS'] = config.get("Peers", "peer_global_DNS")
if "endpoint_allowed_ip" not in search[0]:
update_db['endpoint_allowed_ip'] = config.get("Peers", "peer_endpoint_allowed_ip")
# Not required peers settings (Only for QR code)
if "private_key" not in search[0]:
update_db['private_key'] = ''
if "mtu" not in search[0]:
update_db['mtu'] = config.get("Peers", "peer_mtu")
if "keepalive" not in search[0]:
update_db['keepalive'] = config.get("Peers", "peer_keep_alive")
if "remote_endpoint" not in search[0]:
update_db['remote_endpoint'] = config.get("Peers","remote_endpoint")
if "preshared_key" not in search[0]:
if "PresharedKey" in i.keys():
update_db['preshared_key'] = i["PresharedKey"]
else:
update_db['preshared_key'] = ""
db.update(update_db, peers.id == i['PublicKey'])
# Remove peers no longer exist in WireGuard configuration file # Remove peers no longer exist in WireGuard configuration file
db_key = list(map(lambda a: a['id'], db.all())) 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'])) wg_key = list(map(lambda a: a['PublicKey'], conf_peer_data['Peers']))
for i in db_key: for i in db_key:
if i not in wg_key: if i not in wg_key:
db.remove(peers.id == i) g.cur.execute("DELETE FROM %s WHERE id = '%s'" % (config_name, i))
tic = time.perf_counter() tic = time.perf_counter()
get_latest_handshake(config_name, db, peers) get_latest_handshake(config_name)
get_transfer(config_name, db, peers) get_transfer(config_name)
get_endpoint(config_name, db, peers) get_endpoint(config_name)
get_allowed_ip(db, peers, conf_peer_data) get_allowed_ip(conf_peer_data, config_name)
toc = time.perf_counter() toc = time.perf_counter()
print(f"Finish fetching data in {toc - tic:0.4f} seconds") print(f"Finish fetching data in {toc - tic:0.4f} seconds")
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
# Search for peers # Search for peers
@ -333,24 +314,26 @@ def get_peers(config_name, search, sort_t):
""" """
Frontend Related Functions Frontend Related Functions
""" """
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) get_all_peers_data(config_name)
sem.acquire(timeout=1)
db = TinyDB(os.path.join(db_path, config_name + ".json"))
peer = Query()
if len(search) == 0: if len(search) == 0:
result = db.all() data = g.cur.execute("SELECT * FROM " + config_name).fetchall()
result = [{col[i]: data[k][i] for i in range(len(col))} for k in range(len(data))]
else: else:
result = db.search(peer.name.matches('(.*)(' + re.escape(search) + ')(.*)')) sql = "SELECT * FROM " + config_name + " WHERE name LIKE '%"+search+"%'"
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": 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(d[sort_t].split(",")[0]))
else: else:
result = sorted(result, key=lambda d: d[sort_t]) result = sorted(result, key=lambda d: d[sort_t])
db.close() toc = time.perf_counter()
try: print(f"Finish fetching peers in {toc - tic:0.4f} seconds")
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return result return result
@ -385,24 +368,17 @@ def get_conf_listen_port(config_name):
# Get configuration total data # Get configuration total data
def get_conf_total_data(config_name): def get_conf_total_data(config_name):
sem.acquire(timeout=1) data = g.cur.execute("SELECT total_sent, total_receive, cumu_sent, cumu_receive FROM " + config_name)
db = TinyDB(os.path.join(db_path, config_name + ".json"))
upload_total = 0 upload_total = 0
download_total = 0 download_total = 0
for i in db.all(): for i in data.fetchall():
upload_total += i['total_sent'] upload_total += i[0]
download_total += i['total_receive'] download_total += i[1]
for k in i['traffic']: upload_total += i[2]
upload_total += k['total_sent'] download_total += i[3]
download_total += k['total_receive']
total = round(upload_total + download_total, 4) total = round(upload_total + download_total, 4)
upload_total = round(upload_total, 4) upload_total = round(upload_total, 4)
download_total = round(download_total, 4) download_total = round(download_total, 4)
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return [total, upload_total, download_total] return [total, upload_total, download_total]
@ -419,6 +395,8 @@ def get_conf_list():
for i in os.listdir(wg_conf_path): for i in os.listdir(wg_conf_path):
if regex_match("^(.{1,}).(conf)$", i): if regex_match("^(.{1,}).(conf)$", i):
i = i.replace('.conf', '') i = i.replace('.conf', '')
g.cur.execute(
"CREATE TABLE IF NOT EXISTS " + i + " (id VARCHAR NULL, private_key VARCHAR NULL, DNS VARCHAR NULL, endpoint_allowed_ip VARCHAR NULL, name VARCHAR NULL, total_receive FLOAT NULL, total_sent FLOAT NULL, total_data FLOAT NULL, endpoint VARCHAR NULL, status VARCHAR NULL, latest_handshake VARCHAR NULL, allowed_ip VARCHAR NULL, cumu_receive FLOAT NULL, cumu_sent FLOAT NULL, cumu_data FLOAT NULL, mtu INT NULL, keepalive INT NULL, remote_endpoint VARCHAR NULL, preshared_key VARCHAR NULL)")
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": if temp['status'] == "running":
temp['checked'] = 'checked' temp['checked'] = 'checked'
@ -466,48 +444,25 @@ def f_check_key_match(private_key, public_key, config_name):
if result['status'] == 'failed': if result['status'] == 'failed':
return result return result
else: else:
sem.acquire(timeout=1) sql = "SELECT * FROM " + config_name + " WHERE id = ?"
db = TinyDB(os.path.join(db_path, config_name + ".json")) match = g.cur.execute(sql, (result['data'],)).fetchall()
peers = Query()
match = db.search(peers.id == result['data'])
if len(match) != 1 or result['data'] != public_key: if len(match) != 1 or result['data'] != public_key:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return {'status': 'failed', 'msg': 'Please check your private key, it does not match with the public key.'} return {'status': 'failed', 'msg': 'Please check your private key, it does not match with the public key.'}
else: else:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return {'status': 'success'} return {'status': 'success'}
# Check if there is repeated allowed IP # Check if there is repeated allowed IP
def check_repeat_allowed_ip(public_key, ip, config_name): def check_repeat_allowed_ip(public_key, ip, config_name):
sem.acquire(timeout=1) peer = g.cur.execute("SELECT COUNT(*) FROM " + config_name + " WHERE id = ?", (public_key,)).fetchone()
db = TinyDB(os.path.join(db_path, config_name + ".json")) if peer[0] != 1:
peers = Query()
peer = db.search(peers.id == public_key)
if len(peer) != 1:
return {'status': 'failed', 'msg': 'Peer does not exist'} return {'status': 'failed', 'msg': 'Peer does not exist'}
else: else:
existed_ip = db.search((peers.id != public_key) & (peers.allowed_ip == ip)) existed_ip = g.cur.execute("SELECT COUNT(*) FROM " +
if len(existed_ip) != 0: config_name + " WHERE id != ? AND allowed_ip = ?", (public_key, ip)).fetchone()
db.close() if existed_ip[0] != 0:
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return {'status': 'failed', 'msg': "Allowed IP already taken by another peer."} return {'status': 'failed', 'msg': "Allowed IP already taken by another peer."}
else: else:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return {'status': 'success'} return {'status': 'success'}
@ -516,10 +471,19 @@ Flask Functions
""" """
@app.teardown_request
def close_DB(exception):
if hasattr(g, 'db'):
g.db.commit()
g.db.close()
# Before request # Before request
@app.before_request @app.before_request
def auth_req(): def auth_req():
sem.acquire(timeout=1) if getattr(g, 'db', None) is None:
g.db = connect_db()
g.cur = g.db.cursor()
conf = get_dashboard_conf() conf = get_dashboard_conf()
req = conf.get("Server", "auth_req") req = conf.get("Server", "auth_req")
session['update'] = UPDATE session['update'] = UPDATE
@ -536,10 +500,6 @@ def auth_req():
else: else:
session['message'] = "" session['message'] = ""
conf.clear() conf.clear()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return redirect(url_for("signin")) return redirect(url_for("signin"))
else: else:
if request.endpoint in ['signin', 'signout', 'auth', 'settings', 'update_acct', 'update_pwd', if request.endpoint in ['signin', 'signout', 'auth', 'settings', 'update_acct', 'update_pwd',
@ -595,7 +555,6 @@ def index():
""" """
Index Page Related Index Page Related
""" """
return render_template('index.html', conf=get_conf_list()) return render_template('index.html', conf=get_conf_list())
@ -841,7 +800,7 @@ def get_conf(config_name):
config = get_dashboard_conf() config = get_dashboard_conf()
sort = config.get("Server", "dashboard_sort") sort = config.get("Server", "dashboard_sort")
peer_display_mode = config.get("Peers", "peer_display_mode") peer_display_mode = config.get("Peers", "peer_display_mode")
wg_ip = config.get("Peers","remote_endpoint") wg_ip = config.get("Peers", "remote_endpoint")
if "Address" not in config_interface: if "Address" not in config_interface:
conf_address = "N/A" conf_address = "N/A"
else: else:
@ -864,17 +823,17 @@ def get_conf(config_name):
conf_data['checked'] = "nope" conf_data['checked'] = "nope"
else: else:
conf_data['checked'] = "checked" conf_data['checked'] = "checked"
print(wg_ip)
config.clear() config.clear()
return jsonify(conf_data) return jsonify(conf_data)
# return render_template('get_conf.html', conf_data=conf_data, wg_ip=config.get("Peers","remote_endpoint"), sort_tag=sort, # return render_template('get_conf.html', conf_data=conf_data, wg_ip=config.get("Peers","remote_endpoint"), sort_tag=sort,
# dashboard_refresh_interval=int(config.get("Server", "dashboard_refresh_interval")), peer_display_mode=peer_display_mode) # dashboard_refresh_interval=int(config.get("Server", "dashboard_refresh_interval")), peer_display_mode=peer_display_mode)
# Turn on / off a configuration # Turn on / off a configuration
@app.route('/switch/<config_name>', methods=['GET']) @app.route('/switch/<config_name>', methods=['GET'])
def switch(config_name): def switch(config_name):
if "username" not in session: if "username" not in session:
print("not loggedin") print("User not logged in")
return redirect(url_for("signin")) return redirect(url_for("signin"))
status = get_conf_status(config_name) status = get_conf_status(config_name)
if status == "running": if status == "running":
@ -891,12 +850,10 @@ def switch(config_name):
return redirect('/') return redirect('/')
return redirect(request.referrer) return redirect(request.referrer)
# Add peer # Add peer
@app.route('/add_peer/<config_name>', methods=['POST']) @app.route('/add_peer/<config_name>', methods=['POST'])
def add_peer(config_name): def add_peer(config_name):
sem.acquire(timeout=1)
db = TinyDB(os.path.join(db_path, config_name + ".json"))
peers = Query()
data = request.get_json() data = request.get_json()
public_key = data['public_key'] public_key = data['public_key']
allowed_ips = data['allowed_ips'] allowed_ips = data['allowed_ips']
@ -905,88 +862,40 @@ def add_peer(config_name):
enable_preshared_key = data["enable_preshared_key"] enable_preshared_key = data["enable_preshared_key"]
keys = get_conf_peer_key(config_name) keys = get_conf_peer_key(config_name)
if len(public_key) == 0 or len(dns_addresses) == 0 or len(allowed_ips) == 0 or len(endpoint_allowed_ip) == 0: if len(public_key) == 0 or len(dns_addresses) == 0 or len(allowed_ips) == 0 or len(endpoint_allowed_ip) == 0:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "Please fill in all required box." return "Please fill in all required box."
if not isinstance(keys, list): if not isinstance(keys, list):
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return config_name + " is not running." return config_name + " is not running."
if public_key in keys: if public_key in keys:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "Public key already exist." return "Public key already exist."
if len(db.search(peers.allowed_ip.matches(allowed_ips))) != 0: check_dup_ip = g.cur.execute("SELECT COUNT(*) FROM " + config_name + " WHERE allowed_ip = ?",
db.close() (allowed_ips,)).fetchone()
try: if check_dup_ip[0] != 0:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "Allowed IP already taken by another peer." return "Allowed IP already taken by another peer."
if not check_DNS(dns_addresses): if not check_DNS(dns_addresses):
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "DNS formate is incorrect. Example: 1.1.1.1" return "DNS formate is incorrect. Example: 1.1.1.1"
if not check_Allowed_IPs(endpoint_allowed_ip): if not check_Allowed_IPs(endpoint_allowed_ip):
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "Endpoint Allowed IPs format is incorrect." return "Endpoint Allowed IPs format is incorrect."
if len(data['MTU']) == 0 or not data['MTU'].isdigit(): if len(data['MTU']) == 0 or not data['MTU'].isdigit():
db.close() return "MTU format is not correct."
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "MTU format is not correct."
if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit(): if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit():
db.close() return "Persistent Keepalive format is not correct."
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "Persistent Keepalive format is not correct."
try: try:
if enable_preshared_key == True: if enable_preshared_key:
key = subprocess.check_output("wg genpsk > tmp_psk.txt", shell=True) key = subprocess.check_output("wg genpsk > tmp_psk.txt", shell=True)
status = subprocess.check_output(f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips} preshared-key tmp_psk.txt", status = subprocess.check_output(
shell=True, stderr=subprocess.STDOUT) f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips} preshared-key tmp_psk.txt",
shell=True, stderr=subprocess.STDOUT)
os.remove("tmp_psk.txt") os.remove("tmp_psk.txt")
elif enable_preshared_key == False: elif not enable_preshared_key:
status = subprocess.check_output(f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips}", status = subprocess.check_output(f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips}",
shell=True, stderr=subprocess.STDOUT) shell=True, stderr=subprocess.STDOUT)
status = subprocess.check_output("wg-quick save " + config_name, shell=True, stderr=subprocess.STDOUT) status = subprocess.check_output("wg-quick save " + config_name, shell=True, stderr=subprocess.STDOUT)
get_all_peers_data(config_name) get_all_peers_data(config_name)
db.update({"name": data['name'], "private_key": data['private_key'], "DNS": data['DNS'], sql = "UPDATE " + config_name + " SET name = ?, private_key = ?, DNS = ?, endpoint_allowed_ip = ? WHERE id = ?"
"endpoint_allowed_ip": endpoint_allowed_ip}, g.cur.execute(sql, (data['name'], data['private_key'], data['DNS'], endpoint_allowed_ip, public_key))
peers.id == public_key)
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "true" return "true"
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return exc.output.strip() return exc.output.strip()
@ -995,38 +904,26 @@ 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."
sem.acquire(timeout=1)
db = TinyDB(os.path.join(db_path, config_name + ".json"))
peers = Query()
data = request.get_json() data = request.get_json()
delete_key = data['peer_id'] delete_key = data['peer_id']
keys = get_conf_peer_key(config_name) keys = get_conf_peer_key(config_name)
if not isinstance(keys, list): if not isinstance(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()
return "This key does not exist" return "This key does not exist"
else: else:
try: try:
remove_wg = subprocess.check_output(f"wg set {config_name} peer {delete_key} remove", remove_wg = subprocess.check_output(f"wg set {config_name} peer {delete_key} remove",
shell=True, stderr=subprocess.STDOUT) shell=True, stderr=subprocess.STDOUT)
save_wg = subprocess.check_output(f"wg-quick save {config_name}", save_wg = subprocess.check_output(f"wg-quick save {config_name}",
shell=True, stderr=subprocess.STDOUT) shell=True, stderr=subprocess.STDOUT)
db.remove(peers.id == delete_key) sql = "DELETE FROM " + config_name + " WHERE id = ?"
db.close() g.cur.execute(sql, (delete_key,))
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return "true" return "true"
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return exc.output.strip() return exc.output.strip()
# Save peer settings # Save peer settings
@app.route('/save_peer_setting/<config_name>', methods=['POST']) @app.route('/save_peer_setting/<config_name>', methods=['POST'])
def save_peer_setting(config_name): def save_peer_setting(config_name):
@ -1038,54 +935,22 @@ def save_peer_setting(config_name):
allowed_ip = data['allowed_ip'] allowed_ip = data['allowed_ip']
endpoint_allowed_ip = data['endpoint_allowed_ip'] endpoint_allowed_ip = data['endpoint_allowed_ip']
preshared_key = data['preshared_key'] preshared_key = data['preshared_key']
sem.acquire(timeout=1) check_peer_exist = g.cur.execute("SELECT COUNT(*) FROM " + config_name + " WHERE id = ?", (id,)).fetchone()
db = TinyDB(os.path.join(db_path, config_name + ".json")) if check_peer_exist[0] == 1:
peers = Query()
if len(db.search(peers.id == id)) == 1:
check_ip = check_repeat_allowed_ip(id, allowed_ip, config_name) check_ip = check_repeat_allowed_ip(id, allowed_ip, config_name)
if not check_IP_with_range(endpoint_allowed_ip): if not check_IP_with_range(endpoint_allowed_ip):
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": "Endpoint Allowed IPs format is incorrect."}) return jsonify({"status": "failed", "msg": "Endpoint Allowed IPs format is incorrect."})
if not check_DNS(dns_addresses): if not check_DNS(dns_addresses):
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": "DNS format is incorrect."}) return jsonify({"status": "failed", "msg": "DNS format is incorrect."})
if len(data['MTU']) == 0 or not data['MTU'].isdigit(): if len(data['MTU']) == 0 or not data['MTU'].isdigit():
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": "MTU format is not correct."}) return jsonify({"status": "failed", "msg": "MTU format is not correct."})
if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit(): if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit():
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": "Persistent Keepalive format is not correct."}) return jsonify({"status": "failed", "msg": "Persistent Keepalive format is not correct."})
if private_key != "": if private_key != "":
check_key = f_check_key_match(private_key, id, config_name) check_key = f_check_key_match(private_key, id, config_name)
if check_key['status'] == "failed": if check_key['status'] == "failed":
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify(check_key) return jsonify(check_key)
if check_ip['status'] == "failed": if check_ip['status'] == "failed":
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify(check_ip) return jsonify(check_ip)
try: try:
tmp_psk = open("tmp_edit_psk.txt", "w+") tmp_psk = open("tmp_edit_psk.txt", "w+")
@ -1094,11 +959,6 @@ def save_peer_setting(config_name):
change_psk = subprocess.check_output(f"wg set {config_name} peer {id} preshared-key tmp_edit_psk.txt", change_psk = subprocess.check_output(f"wg set {config_name} peer {id} preshared-key tmp_edit_psk.txt",
shell=True, stderr=subprocess.STDOUT) shell=True, stderr=subprocess.STDOUT)
if change_psk.decode("UTF-8") != "": if change_psk.decode("UTF-8") != "":
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": change_psk.decode("UTF-8")}) return jsonify({"status": "failed", "msg": change_psk.decode("UTF-8")})
if allowed_ip == "": if allowed_ip == "":
allowed_ip = '""' allowed_ip = '""'
@ -1107,40 +967,14 @@ def save_peer_setting(config_name):
shell=True, stderr=subprocess.STDOUT) shell=True, stderr=subprocess.STDOUT)
subprocess.check_output(f'wg-quick save {config_name}', shell=True, stderr=subprocess.STDOUT) subprocess.check_output(f'wg-quick save {config_name}', shell=True, stderr=subprocess.STDOUT)
if change_ip.decode("UTF-8") != "": if change_ip.decode("UTF-8") != "":
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": change_ip.decode("UTF-8")}) return jsonify({"status": "failed", "msg": change_ip.decode("UTF-8")})
db.update( sql = "UPDATE " + config_name + " SET name = ?, private_key = ?, DNS = ?, endpoint_allowed_ip = ?, mtu = ?, keepalive = ?, preshared_key = ? WHERE id = ?"
{ g.cur.execute(sql, (name, private_key, dns_addresses, endpoint_allowed_ip, data["MTU"],
"name": name, data["keep_alive"], preshared_key, id))
"private_key": private_key,
"DNS": dns_addresses,
"endpoint_allowed_ip": endpoint_allowed_ip,
"mtu": data['MTU'],
"keepalive":data['keep_alive'], "preshared_key": preshared_key
}, peers.id == id)
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "success", "msg": ""}) return jsonify({"status": "success", "msg": ""})
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": str(exc.output.decode("UTF-8").strip())}) return jsonify({"status": "failed", "msg": str(exc.output.decode("UTF-8").strip())})
else: else:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify({"status": "failed", "msg": "This peer does not exist."}) return jsonify({"status": "failed", "msg": "This peer does not exist."})
@ -1148,20 +982,13 @@ def save_peer_setting(config_name):
@app.route('/get_peer_data/<config_name>', methods=['POST']) @app.route('/get_peer_data/<config_name>', methods=['POST'])
def get_peer_name(config_name): def get_peer_name(config_name):
data = request.get_json() data = request.get_json()
id = data['id'] peer_id = data['id']
sem.acquire(timeout=1) result = g.cur.execute(
db = TinyDB(os.path.join(db_path, config_name + ".json")) "SELECT name, allowed_ip, DNS, private_key, endpoint_allowed_ip, mtu, keepalive, preshared_key FROM "
peers = Query() + config_name + " WHERE id = ?", (peer_id,)).fetchall()
result = db.search(peers.id == id) data = {"name": result[0][0], "allowed_ip": result[0][1], "DNS": result[0][2],
db.close() "private_key": result[0][3], "endpoint_allowed_ip": result[0][4],
data = {"name": result[0]['name'], "allowed_ip": result[0]['allowed_ip'], "DNS": result[0]['DNS'], "mtu": result[0][5], "keep_alive": result[0][6], "preshared_key": result[0][7]}
"private_key": result[0]['private_key'], "endpoint_allowed_ip": result[0]['endpoint_allowed_ip'],
"mtu": result[0]['mtu'], "keep_alive": result[0]['keepalive'], "preshared_key": result[0]["preshared_key"]}
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return jsonify(data) return jsonify(data)
@ -1190,55 +1017,33 @@ def check_key_match(config_name):
@app.route("/qrcode/<config_name>", methods=['GET']) @app.route("/qrcode/<config_name>", methods=['GET'])
def generate_qrcode(config_name): def generate_qrcode(config_name):
id = request.args.get('id') peer_id = request.args.get('id')
sem.acquire(timeout=1) get_peer = g.cur.execute("SELECT private_key, allowed_ip, DNS, mtu, endpoint_allowed_ip, keepalive, preshared_key FROM "
db = TinyDB(os.path.join(db_path, config_name + ".json")) + config_name + " WHERE id = ?", (peer_id,)).fetchall()
peers = Query()
get_peer = db.search(peers.id == id)
config = get_dashboard_conf() config = get_dashboard_conf()
if len(get_peer) == 1: if len(get_peer) == 1:
peer = get_peer[0] peer = get_peer[0]
if peer['private_key'] != "": if peer[0] != "":
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)
endpoint = config.get("Peers", "remote_endpoint") + ":" + listen_port endpoint = config.get("Peers", "remote_endpoint") + ":" + listen_port
private_key = peer['private_key'] private_key = peer[0]
allowed_ip = peer['allowed_ip'] allowed_ip = peer[1]
dns_addresses = peer['DNS'] dns_addresses = peer[2]
mtu_value = peer['mtu'] mtu_value = peer[3]
endpoint_allowed_ip = peer['endpoint_allowed_ip'] endpoint_allowed_ip = peer[4]
keepalive = peer['keepalive'] keepalive = peer[5]
preshared_key = peer["preshared_key"] preshared_key = peer[6]
conf = {
"public_key": public_key,
"listen_port": listen_port,
"endpoint": endpoint,
"private_key": private_key,
"allowed_ip": allowed_ip,
"DNS": dns_addresses,
"mtu": mtu_value,
"endpoint_allowed_ip": endpoint_allowed_ip,
"keepalive": keepalive,
"preshared_key": preshared_key
}
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
result = "[Interface]\nPrivateKey = "+conf['private_key']+"\nAddress = "+conf['allowed_ip']+"\nMTU = "+conf['mtu']+"\nDNS = "+conf['DNS']\ result = "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nMTU = " \
+"\n\n[Peer]\nPublicKey = "+conf['public_key']+"\nAllowedIPs = "+conf['endpoint_allowed_ip']+"\nPersistentKeepalive = "+conf['keepalive']+"\nEndpoint = "+conf['endpoint'] + str(mtu_value) + "\nDNS = " + dns_addresses + "\n\n[Peer]\nPublicKey = " + public_key \
+ "\nAllowedIPs = " + endpoint_allowed_ip + "\nPersistentKeepalive = " \
+ str(keepalive) + "\nEndpoint = " + endpoint
if preshared_key != "": if preshared_key != "":
result += "\nPresharedKey = "+preshared_key result += "\nPresharedKey = " + preshared_key
return render_template("qrcode.html", i=result) return render_template("qrcode.html", i=result)
else: else:
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return redirect("/configuration/" + config_name) return redirect("/configuration/" + config_name)
@ -1246,30 +1051,29 @@ def generate_qrcode(config_name):
@app.route('/download/<config_name>', methods=['GET']) @app.route('/download/<config_name>', methods=['GET'])
def download(config_name): def download(config_name):
print(request.headers.get('User-Agent')) print(request.headers.get('User-Agent'))
id = request.args.get('id') peer_id = request.args.get('id')
sem.acquire(timeout=1) get_peer = g.cur.execute(
db = TinyDB(os.path.join(db_path, config_name + ".json")) "SELECT private_key, allowed_ip, DNS, mtu, endpoint_allowed_ip, keepalive, preshared_key, name FROM "
peers = Query() + config_name + " WHERE id = ?", (peer_id,)).fetchall()
get_peer = db.search(peers.id == id)
config = get_dashboard_conf() config = get_dashboard_conf()
if len(get_peer) == 1: if len(get_peer) == 1:
peer = get_peer[0] peer = get_peer[0]
if peer['private_key'] != "": if peer[0] != "":
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)
endpoint = config.get("Peers", "remote_endpoint") + ":" + listen_port endpoint = config.get("Peers", "remote_endpoint") + ":" + listen_port
private_key = peer['private_key'] private_key = peer[0]
allowed_ip = peer['allowed_ip'] allowed_ip = peer[1]
dns_addresses = peer['DNS'] dns_addresses = peer[2]
mtu_value = peer['mtu'] mtu_value = peer[3]
endpoint_allowed_ip = peer['endpoint_allowed_ip'] endpoint_allowed_ip = peer[4]
keepalive = peer['keepalive'] keepalive = peer[5]
filename = peer['name'] preshared_key = peer[6]
preshared_key = peer["preshared_key"] filename = peer[7]
if len(filename) == 0: if len(filename) == 0:
filename = "Untitled_Peers" filename = "Untitled_Peer"
else: else:
filename = peer['name'] filename = peer[7]
# Clean filename # Clean filename
illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3", illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3",
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
@ -1282,18 +1086,15 @@ def download(config_name):
filename = filename + "_" + config_name filename = filename + "_" + config_name
psk = "" psk = ""
if preshared_key != "": if preshared_key != "":
psk = "\nPresharedKey = "+preshared_key psk = "\nPresharedKey = " + preshared_key
db.close()
try: def generate():
sem.release() yield "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nDNS = " + \
except RuntimeError as e: dns_addresses + "\nMTU = " + str(mtu_value) + "\n\n[Peer]\nPublicKey = " + \
print("RuntimeError: cannot release un-acquired lock") public_key + "\nAllowedIPs = " + endpoint_allowed_ip + "\nEndpoint = " + \
result = "[Interface]\nPrivateKey = " + private_key + "\nAddress = " + allowed_ip + "\nDNS = " + \ endpoint + "\nPersistentKeepalive = " + str(keepalive) + psk
dns_addresses + "\nMTU = " + mtu_value + "\n\n[Peer]\nPublicKey = " + \ return app.response_class(generate(), mimetype='text/conf',
public_key + "\nAllowedIPs = " + endpoint_allowed_ip + "\nEndpoint = " + \ headers={"Content-Disposition": "attachment;filename=" + filename + ".conf"})
endpoint + "\nPersistentKeepalive = " + keepalive + psk
return app.response_class((yield result), mimetype='text/conf', headers={"Content-Disposition": "attachment;filename=" + filename + ".conf"})
db.close()
return redirect("/configuration/" + config_name) return redirect("/configuration/" + config_name)
@ -1318,25 +1119,19 @@ Dashboard Tools Related
@app.route('/get_ping_ip', methods=['POST']) @app.route('/get_ping_ip', methods=['POST'])
def get_ping_ip(): def get_ping_ip():
config = request.form['config'] config = request.form['config']
sem.acquire(timeout=1) peers = g.cur.execute("SELECT id, name, allowed_ip, endpoint FROM " + config).fetchall()
db = TinyDB(os.path.join(db_path, config + ".json"))
html = "" html = ""
for i in db.all(): for i in peers:
html += '<optgroup label="' + i['name'] + ' - ' + i['id'] + '">' html += '<optgroup label="' + i[1] + ' - ' + i[0] + '">'
allowed_ip = str(i['allowed_ip']).split(",") allowed_ip = str(i[2]).split(",")
for k in allowed_ip: for k in allowed_ip:
k = k.split("/") k = k.split("/")
if len(k) == 2: if len(k) == 2:
html += "<option value=" + k[0] + ">" + k[0] + "</option>" html += "<option value=" + k[0] + ">" + k[0] + "</option>"
endpoint = str(i['endpoint']).split(":") endpoint = str(i[3]).split(":")
if len(endpoint) == 2: if len(endpoint) == 2:
html += "<option value=" + endpoint[0] + ">" + endpoint[0] + "</option>" html += "<option value=" + endpoint[0] + ">" + endpoint[0] + "</option>"
html += "</optgroup>" html += "</optgroup>"
db.close()
try:
sem.release()
except RuntimeError as e:
print("RuntimeError: cannot release un-acquired lock")
return html return html

BIN
src/db/wgdashboard.db Normal file

Binary file not shown.

View File

@ -387,10 +387,8 @@
response["peer_data"].forEach(function(peer){ response["peer_data"].forEach(function(peer){
let total_r = 0; let total_r = 0;
let total_s = 0; let total_s = 0;
for (let i = 0; i < peer["traffic"].length; i++){ total_r += peer["cumu_receive"];
total_r += peer["traffic"][i]["total_receive"]; total_s += peer["cumu_sent"];
total_s += peer["traffic"][i]["total_sent"];
}
let spliter = '<div class="w-100"></div>'; let spliter = '<div class="w-100"></div>';
let peer_name = let peer_name =
'<div class="col-sm display" style="display: flex; align-items: center; margin-bottom: 0.2rem">' + '<div class="col-sm display" style="display: flex; align-items: center; margin-bottom: 0.2rem">' +