1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-10-02 09:30:11 +02:00

v2.3 Final Commit

This commit is contained in:
Donald Cheng Hong Zou 2021-09-08 12:39:25 -04:00
parent 77f6826af9
commit 58784b1e22
10 changed files with 651 additions and 396 deletions

View File

@ -4,9 +4,9 @@
<p align="center"> <p align="center">
<img src="img/logo.png" width="128"> <img alt="Wireguard Dashboard Logo" src="img/logo.png" width="128">
</p> </p>
<h1 align="center"> Wireguard Dashboard</h1> <h1 align="center">Wireguard Dashboard</h1>
<p align="center"> <p align="center">
<img src="http://ForTheBadge.com/images/badges/made-with-python.svg"> <img src="http://ForTheBadge.com/images/badges/made-with-python.svg">
@ -23,10 +23,13 @@
- **Update directly from `wgd.sh`:** Now you can update Wireguard Dashboard directly from the bash script. - **Update directly from `wgd.sh`:** Now you can update Wireguard Dashboard directly from the bash script.
- **Displaying Peers:** You can switch the display mode between list and table in the configuration page. - **Displaying Peers:** You can switch the display mode between list and table in the configuration page.
- 🪚 **Bug Fixed** - 🪚 **Bug Fixed**
- [Peer DNS Validation Fails #67](https://github.com/donaldzou/wireguard-dashboard/issues/67): Added DNS format check - [Peer DNS Validation Fails #67](https://github.com/donaldzou/wireguard-dashboard/issues/67): Added DNS format check. [❤️ @realfian]
- [configparser.NoSectionError: No section: 'Interface' #66](https://github.com/donaldzou/wireguard-dashboard/issues/66): Changed permission requirement for `etc/wireguard` from `744` to `755` - [configparser.NoSectionError: No section: 'Interface' #66](https://github.com/donaldzou/wireguard-dashboard/issues/66): Changed permission requirement for `etc/wireguard` from `744` to `755`. [❤️ @ramalmaty]
- [Feature request: Interface not loading when information missing #73](https://github.com/donaldzou/wireguard-dashboard/issues/73): Fixed when Configuration Address and Listen Port is missing will crash the dashboard. [❤️ @js32]
- [Remote Peer, MTU and PersistentKeepalives added #70](https://github.com/donaldzou/wireguard-dashboard/pull/70): Added MTU, remote peer and Persistent Keepalive. [❤️ @realfian]
- [Fixes DNS check to support search domain #65](https://github.com/donaldzou/wireguard-dashboard/pull/65): Added allow input domain into DNS. [❤️@davejlong]
- **🧐 Other Changes** - **🧐 Other Changes**
- Moved Add Peer Button into the right bottom corner.

View File

@ -1,7 +1,12 @@
"""
< Wireguard Dashbaord > - by Donald Zou [https://github.com/donaldzou]
Under Apache-2.0 License
"""
# Python Built-in Library # Python Built-in Library
import os import os
from flask import Flask, request, render_template, redirect, url_for, session, abort, jsonify from flask import Flask, request, render_template, redirect, url_for, session, abort, jsonify
import subprocess import subprocess
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
import time import time
@ -16,13 +21,10 @@ import ifcfg
from flask_qrcode import QRcode from flask_qrcode import QRcode
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
from icmplib import ping, multiping, traceroute, resolve, Host, Hop from icmplib import ping, multiping, traceroute, resolve, Host, Hop
# Dashboard Version # Dashboard Version
dashboard_version = 'v2.3' dashboard_version = 'v2.3'
# Dashboard Config Name # Dashboard Config Name
dashboard_conf = 'wg-dashboard.ini' dashboard_conf = 'wg-dashboard.ini'
# Default Wireguard IP
wg_ip = ifcfg.default_interface()['inet']
# Upgrade Required # Upgrade Required
update = "" update = ""
# Flask App Configuration # Flask App Configuration
@ -32,7 +34,70 @@ app.config['TEMPLATES_AUTO_RELOAD'] = True
# Enable QR Code Generator # Enable QR Code Generator
QRcode(app) QRcode(app)
"""
Helper Functions
"""
# Regex Match
def regex_match(regex, text):
pattern = re.compile(regex)
return pattern.search(text) is not None
# Check IP format (IPv4 only now)
# TODO: Add IPv6 support
def check_IP(ip):
return regex_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}", ip)
# Clean IP
def clean_IP(ip):
return ip.replace(' ', '')
# Clean IP with range
def clean_IP_with_range(ip):
return clean_IP(ip).split(',')
# Check IP with range (IPv4 only now)
# TODO: Add IPv6 support
def check_IP_with_range(ip):
return regex_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/)){4}(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|" +
"18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)(,|$)", ip)
# Check allowed ips list
def check_Allowed_IPs(ip):
ip = clean_IP_with_range(ip)
for i in ip:
if not check_IP_with_range(i): return False
return True
# Check DNS
def check_DNS(dns):
dns = dns.replace(' ','').split(',')
status = True
for i in dns:
if not (regex_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}", i) or regex_match("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]",i)):
return False
return True
# Check remote endpoint (Both IPv4 address and valid hostname)
# TODO: Add IPv6 support
def check_remote_endpoint(address):
return (regex_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}", address) or regex_match("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]",address))
"""
Dashboard Configuration Related
"""
# Read / Write Dashboard Config File
def get_dashboard_conf():
config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf)
return config
def set_dashboard_conf(config):
config.write(open(dashboard_conf, "w"))
"""
Configuration Related
"""
# Get all keys from a configuration
def get_conf_peer_key(config_name): def get_conf_peer_key(config_name):
try: try:
peer_key = subprocess.check_output("wg show " + config_name + " peers", shell=True) peer_key = subprocess.check_output("wg show " + config_name + " peers", shell=True)
@ -41,7 +106,7 @@ def get_conf_peer_key(config_name):
except Exception: except Exception:
return config_name + " is not running." return config_name + " is not running."
# Get numbers of connected peer of a configuration
def get_conf_running_peer_number(config_name): def get_conf_running_peer_number(config_name):
running = 0 running = 0
# Get latest handshakes # Get latest handshakes
@ -60,12 +125,7 @@ def get_conf_running_peer_number(config_name):
count += 2 count += 2
return running return running
# Read [Interface] section from configuration file
def is_match(regex, text):
pattern = re.compile(regex)
return pattern.search(text) is not None
def read_conf_file_interface(config_name): def read_conf_file_interface(config_name):
conf_location = wg_conf_path + "/" + config_name + ".conf" conf_location = wg_conf_path + "/" + config_name + ".conf"
f = open(conf_location, 'r') f = open(conf_location, 'r')
@ -73,7 +133,7 @@ def read_conf_file_interface(config_name):
data = {} data = {}
peers_start = 0 peers_start = 0
for i in range(len(file)): for i in range(len(file)):
if not is_match("#(.*)", file[i]): if not regex_match("#(.*)", file[i]):
if len(file[i]) > 0: if len(file[i]) > 0:
if file[i] != "[Interface]": if file[i] != "[Interface]":
tmp = re.split(r'\s*=\s*', file[i], 1) tmp = re.split(r'\s*=\s*', file[i], 1)
@ -82,7 +142,7 @@ def read_conf_file_interface(config_name):
f.close() f.close()
return data return data
# Read the whole configuration file
def read_conf_file(config_name): def read_conf_file(config_name):
# Read Configuration File Start # Read Configuration File Start
conf_location = wg_conf_path + "/" + config_name + ".conf" conf_location = wg_conf_path + "/" + config_name + ".conf"
@ -94,7 +154,7 @@ def read_conf_file(config_name):
} }
peers_start = 0 peers_start = 0
for i in range(len(file)): for i in range(len(file)):
if not is_match("#(.*)", file[i]): if not regex_match("#(.*)", file[i]):
if file[i] == "[Peer]": if file[i] == "[Peer]":
peers_start = i peers_start = i
break break
@ -107,7 +167,7 @@ def read_conf_file(config_name):
conf_peers = file[peers_start:] conf_peers = file[peers_start:]
peer = -1 peer = -1
for i in conf_peers: for i in conf_peers:
if not is_match("#(.*)", i): if not regex_match("#(.*)", i):
if i == "[Peer]": if i == "[Peer]":
peer += 1 peer += 1
conf_peer_data["Peers"].append({}) conf_peer_data["Peers"].append({})
@ -121,7 +181,7 @@ def read_conf_file(config_name):
# Read Configuration File End # Read Configuration File End
return conf_peer_data return conf_peer_data
# Get latest handshake from all peers of a configuration
def get_latest_handshake(config_name, db, peers): def get_latest_handshake(config_name, db, peers):
# Get latest handshakes # Get latest handshakes
try: try:
@ -145,7 +205,7 @@ def get_latest_handshake(config_name, db, peers):
db.update({"latest_handshake": "(None)", "status": status}, peers.id == data_usage[count]) db.update({"latest_handshake": "(None)", "status": status}, peers.id == data_usage[count])
count += 2 count += 2
# Get transfer from all peers of a configuration
def get_transfer(config_name, db, peers): def get_transfer(config_name, db, peers):
# Get transfer # Get transfer
try: try:
@ -180,7 +240,7 @@ def get_transfer(config_name, db, peers):
count += 3 count += 3
# Get endpoint from all peers of a configuration
def get_endpoint(config_name, db, peers): def get_endpoint(config_name, db, peers):
# Get endpoint # Get endpoint
try: try:
@ -193,46 +253,56 @@ def get_endpoint(config_name, db, peers):
db.update({"endpoint": data_usage[count + 1]}, peers.id == data_usage[count]) db.update({"endpoint": data_usage[count + 1]}, peers.id == data_usage[count])
count += 2 count += 2
# Get allowed ips from all peers of a configuration
def get_allowed_ip(config_name, db, peers, conf_peer_data): def get_allowed_ip(config_name, db, peers, conf_peer_data):
# Get allowed ip # Get allowed ip
for i in conf_peer_data["Peers"]: for i in conf_peer_data["Peers"]:
db.update({"allowed_ip": i.get('AllowedIPs', '(None)')}, peers.id == i["PublicKey"]) db.update({"allowed_ip": i.get('AllowedIPs', '(None)')}, peers.id == i["PublicKey"])
# Look for new peers from WireGuard
def get_all_peers_data(config_name): def get_all_peers_data(config_name):
db = TinyDB('db/' + config_name + '.json') db = TinyDB('db/' + config_name + '.json')
peers = Query() peers = Query()
conf_peer_data = read_conf_file(config_name) conf_peer_data = read_conf_file(config_name)
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']) search = db.search(peers.id == i['PublicKey'])
if not search: if not search:
db.insert({ db.insert({
"id": i['PublicKey'], "id": i['PublicKey'],
"private_key": "", "private_key": "",
"DNS": "1.1.1.1", "DNS": config.get("Peers", "peer_global_DNS"),
"endpoint_allowed_ip": "0.0.0.0/0", "endpoint_allowed_ip": config.get("Peers","peer_endpoint_allowed_ip"),
"name": "", "name": "",
"total_receive": 0, "total_receive": 0,
"total_sent": 0, "total_sent": 0,
"total_data": 0, "total_data": 0,
"endpoint": 0, "endpoint": "N/A",
"status": 0, "status": "stopped",
"latest_handshake": 0, "latest_handshake": "N/A",
"allowed_ip": 0, "allowed_ip": "N/A",
"traffic": [] "traffic": [],
"mtu": config.get("Peers", "peer_mtu"),
"keepalive": config.get("Peers","peer_keep_alive"),
"remote_endpoint":config.get("Peers","remote_endpoint")
}) })
else: else:
# Update database since V2.2 # Update database since V2.2
print("looking for "+search[0]['id'])
update_db = {} 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]: if "private_key" not in search[0]:
update_db['private_key'] = '' update_db['private_key'] = ''
if "DNS" not in search[0]: if "mtu" not in search[0]:
update_db['DNS'] = '1.1.1.1' update_db['mtu'] = config.get("Peers", "peer_mtu")
if "endpoint_allowed_ip" not in search[0]: if "keepalive" not in search[0]:
update_db['endpoint_allowed_ip'] = '0.0.0.0/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")
db.update(update_db, peers.id == i['PublicKey']) 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['id'], db.all()))
@ -240,10 +310,6 @@ def get_all_peers_data(config_name):
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) db.remove(peers.id == i)
print(db_key)
print(wg_key)
tic = time.perf_counter() tic = time.perf_counter()
get_latest_handshake(config_name, db, peers) get_latest_handshake(config_name, db, peers)
get_transfer(config_name, db, peers) get_transfer(config_name, db, peers)
@ -253,12 +319,14 @@ def get_all_peers_data(config_name):
print(f"Finish fetching data in {toc - tic:0.4f} seconds") print(f"Finish fetching data in {toc - tic:0.4f} seconds")
db.close() db.close()
"""
Frontend Related Functions
"""
# Search for peers
def get_peers(config_name, search, sort_t): def get_peers(config_name, search, sort_t):
get_all_peers_data(config_name) get_all_peers_data(config_name)
db = TinyDB('db/' + config_name + '.json') db = TinyDB('db/' + config_name + '.json')
peer = Query() peer = Query()
print(search)
if len(search) == 0: if len(search) == 0:
result = db.all() result = db.all()
else: else:
@ -268,6 +336,9 @@ def get_peers(config_name, search, sort_t):
return result return result
# Get configuration public key
def get_conf_pub_key(config_name): def get_conf_pub_key(config_name):
conf = configparser.ConfigParser(strict=False) conf = configparser.ConfigParser(strict=False)
conf.read(wg_conf_path + "/" + config_name + ".conf") conf.read(wg_conf_path + "/" + config_name + ".conf")
@ -276,15 +347,21 @@ def get_conf_pub_key(config_name):
conf.clear() conf.clear()
return pub.decode().strip("\n") return pub.decode().strip("\n")
# Get configuration listen port
def get_conf_listen_port(config_name): def get_conf_listen_port(config_name):
conf = configparser.ConfigParser(strict=False) conf = configparser.ConfigParser(strict=False)
conf.read(wg_conf_path + "/" + config_name + ".conf") conf.read(wg_conf_path + "/" + config_name + ".conf")
port = ""
try:
port = conf.get("Interface", "ListenPort") port = conf.get("Interface", "ListenPort")
except:
if get_conf_status(config_name) == "running":
port = subprocess.check_output("wg show "+config_name+" listen-port", shell=True)
port = port.decode("UTF-8")
conf.clear() conf.clear()
return port return port
# Get configuration total data
def get_conf_total_data(config_name): def get_conf_total_data(config_name):
db = TinyDB('db/' + config_name + '.json') db = TinyDB('db/' + config_name + '.json')
upload_total = 0 upload_total = 0
@ -301,7 +378,7 @@ def get_conf_total_data(config_name):
db.close() db.close()
return [total, upload_total, download_total] return [total, upload_total, download_total]
# Get configuration status
def get_conf_status(config_name): def get_conf_status(config_name):
ifconfig = dict(ifcfg.interfaces().items()) ifconfig = dict(ifcfg.interfaces().items())
if config_name in ifconfig.keys(): if config_name in ifconfig.keys():
@ -309,11 +386,11 @@ def get_conf_status(config_name):
else: else:
return "stopped" return "stopped"
# Get all configuration as a list
def get_conf_list(): def get_conf_list():
conf = [] conf = []
for i in os.listdir(wg_conf_path): for i in os.listdir(wg_conf_path):
if is_match("^(.{1,}).(conf)$", i): if regex_match("^(.{1,}).(conf)$", i):
i = i.replace('.conf', '') i = i.replace('.conf', '')
temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)} temp = {"conf": i, "status": get_conf_status(i), "public_key": get_conf_pub_key(i)}
if temp['status'] == "running": if temp['status'] == "running":
@ -325,8 +402,8 @@ def get_conf_list():
conf = sorted(conf, key=itemgetter('conf')) conf = sorted(conf, key=itemgetter('conf'))
return conf return conf
# Generate private key
def genKeys(): def gen_private_key():
gen = subprocess.check_output('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt', gen = subprocess.check_output('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt',
shell=True) shell=True)
private = open('private_key.txt') private = open('private_key.txt')
@ -340,8 +417,8 @@ def genKeys():
os.remove('public_key.txt') os.remove('public_key.txt')
return data return data
# Generate public key
def genPubKey(private_key): def gen_public_key(private_key):
pri_key_file = open('private_key.txt', 'w') pri_key_file = open('private_key.txt', 'w')
pri_key_file.write(private_key) pri_key_file.write(private_key)
pri_key_file.close() pri_key_file.close()
@ -356,9 +433,9 @@ def genPubKey(private_key):
os.remove('private_key.txt') os.remove('private_key.txt')
return {"status": 'failed', "msg": "Key is not the correct length or format", "data": ""} return {"status": 'failed', "msg": "Key is not the correct length or format", "data": ""}
# Check if private key and public key match
def checkKeyMatch(private_key, public_key, config_name): def checkKeyMatch(private_key, public_key, config_name):
result = genPubKey(private_key) result = gen_public_key(private_key)
if result['status'] == 'failed': if result['status'] == 'failed':
return result return result
else: else:
@ -370,8 +447,8 @@ def checkKeyMatch(private_key, public_key, config_name):
else: else:
return {'status': 'success'} return {'status': 'success'}
# Check if there is repeated allowed IP
def checkAllowedIP(public_key, ip, config_name): def check_repeat_allowed_IP(public_key, ip, config_name):
db = TinyDB('db/' + config_name + '.json') db = TinyDB('db/' + config_name + '.json')
peers = Query() peers = Query()
peer = db.search(peers.id == public_key) peer = db.search(peers.id == public_key)
@ -385,30 +462,11 @@ def checkAllowedIP(public_key, ip, config_name):
return {'status': 'success'} return {'status': 'success'}
def checkIp(ip): """
return is_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}", ip) Flask Functions
"""
def cleanIp(ip):
return ip.replace(' ', '')
def cleanIpWithRange(ip):
return cleanIp(ip).split(',')
def checkIpWithRange(ip):
return is_match("((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/)){4}(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|"+
"18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)(,|$)", ip)
def checkAllowedIPs(ip):
ip = cleanIpWithRange(ip)
for i in ip:
if not checkIpWithRange(i): return False
return True
# Before request
@app.before_request @app.before_request
def auth_req(): def auth_req():
conf = configparser.ConfigParser(strict=False) conf = configparser.ConfigParser(strict=False)
@ -433,7 +491,10 @@ def auth_req():
'update_app_ip_port', 'update_wg_conf_path']: 'update_app_ip_port', 'update_wg_conf_path']:
return redirect(url_for("index")) return redirect(url_for("index"))
"""
Sign In / Sign Out
"""
#Sign In
@app.route('/signin', methods=['GET']) @app.route('/signin', methods=['GET'])
def signin(): def signin():
message = "" message = ""
@ -442,7 +503,7 @@ def signin():
session.pop("message") session.pop("message")
return render_template('signin.html', message=message) return render_template('signin.html', message=message)
#Sign Out
@app.route('/signout', methods=['GET']) @app.route('/signout', methods=['GET'])
def signout(): def signout():
if "username" in session: if "username" in session:
@ -450,7 +511,34 @@ def signout():
message = "Sign out successfully!" message = "Sign out successfully!"
return render_template('signin.html', message=message) return render_template('signin.html', message=message)
# Authentication
@app.route('/auth', methods=['POST'])
def auth():
config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf)
password = hashlib.sha256(request.form['password'].encode())
if password.hexdigest() == config["Account"]["password"] and request.form['username'] == config["Account"][
"username"]:
session['username'] = request.form['username']
config.clear()
return redirect(url_for("index"))
else:
session['message'] = "Username or Password is incorrect."
config.clear()
return redirect(url_for("signin"))
"""
Index Page Related
"""
@app.route('/', methods=['GET'])
def index():
update = check_update()
return render_template('index.html', conf=get_conf_list())
"""
Setting Page Related
"""
# Setting Page
@app.route('/settings', methods=['GET']) @app.route('/settings', methods=['GET'])
def settings(): def settings():
message = "" message = ""
@ -467,25 +555,12 @@ def settings():
app_ip=config.get("Server", "app_ip"), app_port=config.get("Server", "app_port"), app_ip=config.get("Server", "app_ip"), app_port=config.get("Server", "app_port"),
required_auth=required_auth, wg_conf_path=config.get("Server", "wg_conf_path"), required_auth=required_auth, wg_conf_path=config.get("Server", "wg_conf_path"),
peer_global_DNS=config.get("Peers", "peer_global_DNS"), peer_global_DNS=config.get("Peers", "peer_global_DNS"),
peer_endpoint_allowed_ip=config.get("Peers", "peer_endpoint_allowed_ip")) peer_endpoint_allowed_ip=config.get("Peers", "peer_endpoint_allowed_ip"),
peer_mtu=config.get("Peers", "peer_mtu"),
peer_keepalive=config.get("Peers","peer_keep_alive"),
@app.route('/auth', methods=['POST']) peer_remote_endpoint=config.get("Peers","remote_endpoint"))
def auth():
config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf)
password = hashlib.sha256(request.form['password'].encode())
if password.hexdigest() == config["Account"]["password"] and request.form['username'] == config["Account"][
"username"]:
session['username'] = request.form['username']
config.clear()
return redirect(url_for("index"))
else:
session['message'] = "Username or Password is incorrect."
config.clear()
return redirect(url_for("signin"))
# Update account username
@app.route('/update_acct', methods=['POST']) @app.route('/update_acct', methods=['POST'])
def update_acct(): def update_acct():
if len(request.form['username']) == 0: if len(request.form['username']) == 0:
@ -508,46 +583,75 @@ def update_acct():
config.clear() config.clear()
return redirect(url_for("settings")) return redirect(url_for("settings"))
# Update peer default settting
@app.route('/update_peer_default_config', methods=['POST']) @app.route('/update_peer_default_config', methods=['POST'])
def update_peer_default_config(): def update_peer_default_config():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf) config.read(dashboard_conf)
if len(request.form['peer_endpoint_allowed_ip']) == 0 or len(request.form['peer_global_DNS']) == 0: if len(request.form['peer_endpoint_allowed_ip']) == 0 or \
session['message'] = "Peer DNS or Peer Endpoint Allowed IP cannot be empty." len(request.form['peer_global_DNS']) == 0 or \
len(request.form['peer_remote_endpoint']) == 0:
session['message'] = "Please fill in all required boxes."
session['message_status'] = "danger" session['message_status'] = "danger"
return redirect(url_for("settings")) return redirect(url_for("settings"))
# Check DNS Format # Check DNS Format
DNS = request.form['peer_global_DNS'] DNS = request.form['peer_global_DNS']
DNS = cleanIp(DNS) if not check_DNS(DNS):
if not checkIp(DNS): session['message'] = "Peer DNS Format Incorrect."
session['message'] = "Peer DNS Format Incorrect. Example: 1.1.1.1"
session['message_status'] = "danger" session['message_status'] = "danger"
return redirect(url_for("settings")) return redirect(url_for("settings"))
DNS = DNS.replace(" ","").split(',')
DNS = ",".join(DNS)
# Check Endpoint Allowed IPs # Check Endpoint Allowed IPs
ip = request.form['peer_endpoint_allowed_ip'] ip = request.form['peer_endpoint_allowed_ip']
if not checkAllowedIPs(ip): if not check_Allowed_IPs(ip):
session['message'] = "Peer Endpoint Allowed IPs Format Incorrect. Example: 192.168.1.1/32 or 192.168.1.1/32,192.168.1.2/32"
session['message_status'] = "danger"
return redirect(url_for("settings"))
# Check MTU Format
if len(request.form['peer_mtu']) > 0:
try:
mtu = int(request.form['peer_mtu'])
except:
session['message'] = "MTU format is incorrect."
session['message_status'] = "danger"
return redirect(url_for("settings"))
# Check keepalive Format
if len(request.form['peer_keep_alive']) > 0:
try:
mtu = int(request.form['peer_keep_alive'])
except:
session['message'] = "Persistent keepalive format is incorrect."
session['message_status'] = "danger"
return redirect(url_for("settings"))
# Check peer remote endpoint
if not check_remote_endpoint(request.form['peer_remote_endpoint']):
session[ session[
'message'] = "Peer Endpoint Allowed IPs Format Incorrect. Example: 192.168.1.1/32 or 192.168.1.1/32,192.168.1.2/32" 'message'] = "Peer Remote Endpoint format is incorrect. It can only be a valid IP address or valid domain (without http:// or https://). "
session['message_status'] = "danger" session['message_status'] = "danger"
return redirect(url_for("settings")) return redirect(url_for("settings"))
config.set("Peers", "peer_endpoint_allowed_ip", ','.join(cleanIpWithRange(ip))) config.set("Peers", "remote_endpoint", request.form['peer_remote_endpoint'])
config.set("Peers", "peer_global_DNS", request.form['peer_global_DNS']) config.set("Peers", "peer_keep_alive", request.form['peer_keep_alive'])
config.set("Peers", "peer_mtu", request.form['peer_mtu'])
config.set("Peers", "peer_endpoint_allowed_ip", ','.join(clean_IP_with_range(ip)))
config.set("Peers", "peer_global_DNS", DNS)
try: try:
config.write(open(dashboard_conf, "w")) config.write(open(dashboard_conf, "w"))
session['message'] = "DNS and Enpoint Allowed IP update successfully!" session['message'] = "Peer Default Settings update successfully!"
session['message_status'] = "success" session['message_status'] = "success"
config.clear() config.clear()
return redirect(url_for("settings")) return redirect(url_for("settings"))
except Exception: except Exception:
session['message'] = "DNS and Enpoint Allowed IP update failed." session['message'] = "Peer Default Settings update failed."
session['message_status'] = "danger" session['message_status'] = "danger"
config.clear() config.clear()
return redirect(url_for("settings")) return redirect(url_for("settings"))
# Update dashboard password
@app.route('/update_pwd', methods=['POST']) @app.route('/update_pwd', methods=['POST'])
def update_pwd(): def update_pwd():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -578,7 +682,7 @@ def update_pwd():
config.clear() config.clear()
return redirect(url_for("settings")) return redirect(url_for("settings"))
# Update dashboard IP and port
@app.route('/update_app_ip_port', methods=['POST']) @app.route('/update_app_ip_port', methods=['POST'])
def update_app_ip_port(): def update_app_ip_port():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -589,7 +693,7 @@ def update_app_ip_port():
config.clear() config.clear()
os.system('bash wgd.sh restart') os.system('bash wgd.sh restart')
# Update WireGuard configuration file path
@app.route('/update_wg_conf_path', methods=['POST']) @app.route('/update_wg_conf_path', methods=['POST'])
def update_wg_conf_path(): def update_wg_conf_path():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -601,7 +705,10 @@ def update_wg_conf_path():
config.clear() config.clear()
os.system('bash wgd.sh restart') os.system('bash wgd.sh restart')
"""
Configuration Page Related
"""
# Update configuration sorting
@app.route('/update_dashboard_sort', methods=['POST']) @app.route('/update_dashboard_sort', methods=['POST'])
def update_dashbaord_sort(): def update_dashbaord_sort():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -616,7 +723,7 @@ def update_dashbaord_sort():
config.clear() config.clear()
return "true" return "true"
# Update configuration refresh interval
@app.route('/update_dashboard_refresh_interval', methods=['POST']) @app.route('/update_dashboard_refresh_interval', methods=['POST'])
def update_dashboard_refresh_interval(): def update_dashboard_refresh_interval():
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -626,71 +733,7 @@ def update_dashboard_refresh_interval():
config.clear() config.clear()
return "true" return "true"
# Configuration Page
@app.route('/get_ping_ip', methods=['POST'])
def get_ping_ip():
config = request.form['config']
db = TinyDB('db/' + config + '.json')
html = ""
for i in db.all():
html += '<optgroup label="' + i['name'] + ' - ' + i['id'] + '">'
allowed_ip = str(i['allowed_ip']).split(",")
for k in allowed_ip:
k = k.split("/")
if len(k) == 2:
html += "<option value=" + k[0] + ">" + k[0] + "</option>"
endpoint = str(i['endpoint']).split(":")
if len(endpoint) == 2:
html += "<option value=" + endpoint[0] + ">" + endpoint[0] + "</option>"
html += "</optgroup>"
return html
@app.route('/ping_ip', methods=['POST'])
def ping_ip():
try:
result = ping('' + request.form['ip'] + '', count=int(request.form['count']), privileged=True, source=None)
returnjson = {
"address": result.address,
"is_alive": result.is_alive,
"min_rtt": result.min_rtt,
"avg_rtt": result.avg_rtt,
"max_rtt": result.max_rtt,
"package_sent": result.packets_sent,
"package_received": result.packets_received,
"package_loss": result.packet_loss
}
if returnjson['package_loss'] == 1.0:
returnjson['package_loss'] = returnjson['package_sent']
return jsonify(returnjson)
except Exception:
return "Error"
@app.route('/traceroute_ip', methods=['POST'])
def traceroute_ip():
try:
result = traceroute('' + request.form['ip'] + '', first_hop=1, max_hops=30, count=1, fast=True)
returnjson = []
last_distance = 0
for hop in result:
if last_distance + 1 != hop.distance:
returnjson.append({"hop": "*", "ip": "*", "avg_rtt": "", "min_rtt": "", "max_rtt": ""})
returnjson.append({"hop": hop.distance, "ip": hop.address, "avg_rtt": hop.avg_rtt, "min_rtt": hop.min_rtt,
"max_rtt": hop.max_rtt})
last_distance = hop.distance
return jsonify(returnjson)
except Exception:
return "Error"
@app.route('/', methods=['GET'])
def index():
return render_template('index.html', conf=get_conf_list())
@app.route('/configuration/<config_name>', methods=['GET']) @app.route('/configuration/<config_name>', methods=['GET'])
def conf(config_name): def conf(config_name):
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
@ -712,9 +755,12 @@ def conf(config_name):
return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data, return render_template('configuration.html', conf=get_conf_list(), conf_data=conf_data,
dashboard_refresh_interval=int(config.get("Server", "dashboard_refresh_interval")), dashboard_refresh_interval=int(config.get("Server", "dashboard_refresh_interval")),
DNS=config.get("Peers", "peer_global_DNS"), DNS=config.get("Peers", "peer_global_DNS"),
endpoint_allowed_ip=config.get("Peers", "peer_endpoint_allowed_ip"), title=config_name) endpoint_allowed_ip=config.get("Peers", "peer_endpoint_allowed_ip"),
title=config_name,
mtu=config.get("Peers","peer_MTU"),
keep_alive=config.get("Peers","peer_keep_alive"))
# Get configuration details
@app.route('/get_config/<config_name>', methods=['GET']) @app.route('/get_config/<config_name>', methods=['GET'])
def get_conf(config_name): def get_conf(config_name):
config_interface = read_conf_file_interface(config_name) config_interface = read_conf_file_interface(config_name)
@ -725,6 +771,10 @@ def get_conf(config_name):
config.read(dashboard_conf) config.read(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")
if "Address" not in config_interface.keys():
conf_address = "N/A"
else:
conf_address = config_interface['Address']
conf_data = { conf_data = {
"peer_data": get_peers(config_name, search, sort), "peer_data": get_peers(config_name, search, sort),
"name": config_name, "name": config_name,
@ -733,16 +783,17 @@ def get_conf(config_name):
"public_key": get_conf_pub_key(config_name), "public_key": get_conf_pub_key(config_name),
"listen_port": get_conf_listen_port(config_name), "listen_port": get_conf_listen_port(config_name),
"running_peer": get_conf_running_peer_number(config_name), "running_peer": get_conf_running_peer_number(config_name),
"conf_address": config_interface['Address'] "conf_address": conf_address
} }
if conf_data['status'] == "stopped": if conf_data['status'] == "stopped":
conf_data['checked'] = "nope" conf_data['checked'] = "nope"
else: else:
conf_data['checked'] = "checked" conf_data['checked'] = "checked"
return render_template('get_conf.html', conf_data=conf_data, wg_ip=wg_ip, sort_tag=sort, print(config.get("Peers","remote_endpoint"))
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
@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:
@ -762,7 +813,7 @@ def switch(config_name):
return redirect(request.referrer) return redirect(request.referrer)
# 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):
db = TinyDB("db/" + config_name + ".json") db = TinyDB("db/" + config_name + ".json")
@ -781,12 +832,20 @@ def add_peer(config_name):
return "Public key already exist." return "Public key already exist."
if len(db.search(peers.allowed_ip.matches(allowed_ips))) != 0: if len(db.search(peers.allowed_ip.matches(allowed_ips))) != 0:
return "Allowed IP already taken by another peer." return "Allowed IP already taken by another peer."
if not checkIp(DNS): if not check_DNS(DNS):
return "DNS formate is incorrect. Example: 1.1.1.1" return "DNS formate is incorrect. Example: 1.1.1.1"
if not checkAllowedIPs(endpoint_allowed_ip): if not check_Allowed_IPs(endpoint_allowed_ip):
return "Endpoint Allowed IPs format is incorrect." return "Endpoint Allowed IPs format is incorrect."
else: if len(data['MTU']) != 0:
status = "" try:
mtu = int(data['MTU'])
except:
return "MTU format is not correct."
if len(data['keep_alive']) != 0:
try:
keep_alive = int(data['keep_alive'])
except:
return "Persistent Keepalive format is not correct."
try: try:
status = subprocess.check_output( status = subprocess.check_output(
"wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True, "wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True,
@ -802,7 +861,7 @@ def add_peer(config_name):
db.close() db.close()
return exc.output.strip() return exc.output.strip()
# Remove peer
@app.route('/remove_peer/<config_name>', methods=['POST']) @app.route('/remove_peer/<config_name>', methods=['POST'])
def remove_peer(config_name): def remove_peer(config_name):
if get_conf_status(config_name) == "stopped": if get_conf_status(config_name) == "stopped":
@ -828,7 +887,7 @@ def remove_peer(config_name):
except subprocess.CalledProcessError as exc: except subprocess.CalledProcessError as exc:
return exc.output.strip() return exc.output.strip()
# 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):
data = request.get_json() data = request.get_json()
@ -841,11 +900,21 @@ def save_peer_setting(config_name):
db = TinyDB("db/" + config_name + ".json") db = TinyDB("db/" + config_name + ".json")
peers = Query() peers = Query()
if len(db.search(peers.id == id)) == 1: if len(db.search(peers.id == id)) == 1:
check_ip = checkAllowedIP(id, allowed_ip, config_name) check_ip = check_repeat_allowed_IP(id, allowed_ip, config_name)
if not checkIpWithRange(endpoint_allowed_ip): if not check_IP_with_range(endpoint_allowed_ip):
return jsonify({"status": "failed", "msg": "Endpoint Allowed IPs format is incorrect."}) return jsonify({"status": "failed", "msg": "Endpoint Allowed IPs format is incorrect."})
if not checkIp(DNS): if not check_DNS(DNS):
return jsonify({"status": "failed", "msg": "DNS format is incorrect."}) return jsonify({"status": "failed", "msg": "DNS format is incorrect."})
if len(data['MTU']) != 0:
try:
mtu = int(data['MTU'])
except:
return jsonify({"status": "failed", "msg": "MTU format is not correct."})
if len(data['keep_alive']) != 0:
try:
keep_alive = int(data['keep_alive'])
except:
return jsonify({"status": "failed", "msg": "Persistent Keepalive format is not correct."})
if private_key != "": if private_key != "":
check_key = checkKeyMatch(private_key, id, config_name) check_key = checkKeyMatch(private_key, id, config_name)
if check_key['status'] == "failed": if check_key['status'] == "failed":
@ -861,7 +930,10 @@ def save_peer_setting(config_name):
if change_ip.decode("UTF-8") != "": if change_ip.decode("UTF-8") != "":
return jsonify({"status": "failed", "msg": change_ip.decode("UTF-8")}) return jsonify({"status": "failed", "msg": change_ip.decode("UTF-8")})
db.update( db.update(
{"name": name, "private_key": private_key, "DNS": DNS, "endpoint_allowed_ip": endpoint_allowed_ip}, {"name": name, "private_key": private_key,
"DNS": DNS, "endpoint_allowed_ip": endpoint_allowed_ip,
"mtu": data['MTU'],
"keepalive":data['keep_alive']},
peers.id == id) peers.id == id)
db.close() db.close()
return jsonify({"status": "success", "msg": ""}) return jsonify({"status": "success", "msg": ""})
@ -870,7 +942,7 @@ def save_peer_setting(config_name):
else: else:
return jsonify({"status": "failed", "msg": "This peer does not exist."}) return jsonify({"status": "failed", "msg": "This peer does not exist."})
# Get peer settings
@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()
@ -880,22 +952,23 @@ def get_peer_name(config_name):
result = db.search(peers.id == id) result = db.search(peers.id == id)
db.close() db.close()
data = {"name": result[0]['name'], "allowed_ip": result[0]['allowed_ip'], "DNS": result[0]['DNS'], data = {"name": result[0]['name'], "allowed_ip": result[0]['allowed_ip'], "DNS": result[0]['DNS'],
"private_key": result[0]['private_key'], "endpoint_allowed_ip": result[0]['endpoint_allowed_ip']} "private_key": result[0]['private_key'], "endpoint_allowed_ip": result[0]['endpoint_allowed_ip'],
"mtu": result[0]['mtu'], "keep_alive": result[0]['keepalive']}
return jsonify(data) return jsonify(data)
# Generate a private key
@app.route('/generate_peer', methods=['GET']) @app.route('/generate_peer', methods=['GET'])
def generate_peer(): def generate_peer():
return jsonify(genKeys()) return jsonify(gen_private_key())
# Generate a public key from a private key
@app.route('/generate_public_key', methods=['POST']) @app.route('/generate_public_key', methods=['POST'])
def generate_public_key(): def generate_public_key():
data = request.get_json() data = request.get_json()
private_key = data['private_key'] private_key = data['private_key']
return jsonify(genPubKey(private_key)) return jsonify(gen_public_key(private_key))
# Check if both key match
@app.route('/check_key_match/<config_name>', methods=['POST']) @app.route('/check_key_match/<config_name>', methods=['POST'])
def check_key_match(config_name): def check_key_match(config_name):
data = request.get_json() data = request.get_json()
@ -903,23 +976,21 @@ def check_key_match(config_name):
public_key = data['public_key'] public_key = data['public_key']
return jsonify(checkKeyMatch(private_key, public_key, config_name)) return jsonify(checkKeyMatch(private_key, public_key, config_name))
# Download configuration file
@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') id = request.args.get('id')
db = TinyDB("db/" + config_name + ".json") db = TinyDB("db/" + config_name + ".json")
peers = Query() peers = Query()
print(id)
get_peer = db.search(peers.id == id) get_peer = db.search(peers.id == id)
print(get_peer) 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['private_key'] != "":
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 = wg_ip + ":" + listen_port endpoint = config.get("Peers","remote_endpoint") + ":" + listen_port
private_key = peer['private_key'] private_key = peer['private_key']
allowed_ip = peer['allowed_ip'] allowed_ip = peer['allowed_ip']
DNS = peer['DNS'] DNS = peer['DNS']
@ -935,7 +1006,6 @@ def download(config_name):
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"] "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
for i in illegal_filename: for i in illegal_filename:
filename = filename.replace(i, "") filename = filename.replace(i, "")
print(filename)
if len(filename) == 0: if len(filename) == 0:
filename = "Untitled_Peer" filename = "Untitled_Peer"
filename = "".join(filename.split(' ')) filename = "".join(filename.split(' '))
@ -950,9 +1020,9 @@ def download(config_name):
else: else:
return redirect("/configuration/" + config_name) return redirect("/configuration/" + config_name)
# Switch peer displate mode
@app.route('/switch_display_mode/<mode>', methods=['GET']) @app.route('/switch_display_mode/<mode>', methods=['GET'])
def switch_display_mode(mode): def switch_display_mode(mode):
print(mode)
if mode in ['list','grid']: if mode in ['list','grid']:
config.read(dashboard_conf) config.read(dashboard_conf)
config.set("Peers", "peer_display_mode", mode) config.set("Peers", "peer_display_mode", mode)
@ -962,20 +1032,85 @@ def switch_display_mode(mode):
return "false" return "false"
"""
Dashboard Tools Related
"""
# Get all IP for ping
@app.route('/get_ping_ip', methods=['POST'])
def get_ping_ip():
config = request.form['config']
db = TinyDB('db/' + config + '.json')
html = ""
for i in db.all():
html += '<optgroup label="' + i['name'] + ' - ' + i['id'] + '">'
allowed_ip = str(i['allowed_ip']).split(",")
for k in allowed_ip:
k = k.split("/")
if len(k) == 2:
html += "<option value=" + k[0] + ">" + k[0] + "</option>"
endpoint = str(i['endpoint']).split(":")
if len(endpoint) == 2:
html += "<option value=" + endpoint[0] + ">" + endpoint[0] + "</option>"
html += "</optgroup>"
return html
# Ping IP
@app.route('/ping_ip', methods=['POST'])
def ping_ip():
try:
result = ping('' + request.form['ip'] + '', count=int(request.form['count']), privileged=True, source=None)
returnjson = {
"address": result.address,
"is_alive": result.is_alive,
"min_rtt": result.min_rtt,
"avg_rtt": result.avg_rtt,
"max_rtt": result.max_rtt,
"package_sent": result.packets_sent,
"package_received": result.packets_received,
"package_loss": result.packet_loss
}
if returnjson['package_loss'] == 1.0:
returnjson['package_loss'] = returnjson['package_sent']
return jsonify(returnjson)
except Exception:
return "Error"
# Traceroute IP
@app.route('/traceroute_ip', methods=['POST'])
def traceroute_ip():
try:
result = traceroute('' + request.form['ip'] + '', first_hop=1, max_hops=30, count=1, fast=True)
returnjson = []
last_distance = 0
for hop in result:
if last_distance + 1 != hop.distance:
returnjson.append({"hop": "*", "ip": "*", "avg_rtt": "", "min_rtt": "", "max_rtt": ""})
returnjson.append({"hop": hop.distance, "ip": hop.address, "avg_rtt": hop.avg_rtt, "min_rtt": hop.min_rtt,
"max_rtt": hop.max_rtt})
last_distance = hop.distance
return jsonify(returnjson)
except Exception:
return "Error"
"""
Dashboard Initialization
"""
def init_dashboard(): def init_dashboard():
# Set Default INI File # Set Default INI File
if not os.path.isfile("wg-dashboard.ini"): if not os.path.isfile("wg-dashboard.ini"):
conf_file = open("wg-dashboard.ini", "w+") conf_file = open("wg-dashboard.ini", "w+")
config = configparser.ConfigParser(strict=False) config = configparser.ConfigParser(strict=False)
config.read(dashboard_conf) config.read(dashboard_conf)
# Defualt dashboard account setting
if "Account" not in config: if "Account" not in config:
config['Account'] = {} config['Account'] = {}
if "username" not in config['Account']: if "username" not in config['Account']:
config['Account']['username'] = 'admin' config['Account']['username'] = 'admin'
if "password" not in config['Account']: if "password" not in config['Account']:
config['Account']['password'] = '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918' config['Account']['password'] = '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918'
# Defualt dashboard server setting
if "Server" not in config: if "Server" not in config:
config['Server'] = {} config['Server'] = {}
if 'wg_conf_path' not in config['Server']: if 'wg_conf_path' not in config['Server']:
@ -992,6 +1127,7 @@ def init_dashboard():
config['Server']['dashboard_refresh_interval'] = '60000' config['Server']['dashboard_refresh_interval'] = '60000'
if 'dashboard_sort' not in config['Server']: if 'dashboard_sort' not in config['Server']:
config['Server']['dashboard_sort'] = 'status' config['Server']['dashboard_sort'] = 'status'
# Defualt dashboard peers setting
if "Peers" not in config: if "Peers" not in config:
config['Peers'] = {} config['Peers'] = {}
if 'peer_global_DNS' not in config['Peers']: if 'peer_global_DNS' not in config['Peers']:
@ -1000,10 +1136,18 @@ def init_dashboard():
config['Peers']['peer_endpoint_allowed_ip'] = '0.0.0.0/0' config['Peers']['peer_endpoint_allowed_ip'] = '0.0.0.0/0'
if 'peer_display_mode' not in config['Peers']: if 'peer_display_mode' not in config['Peers']:
config['Peers']['peer_display_mode'] = 'grid' config['Peers']['peer_display_mode'] = 'grid'
if 'remote_endpoint' not in config['Peers']:
config['Peers']['remote_endpoint'] = ifcfg.default_interface()['inet']
if 'peer_MTU' not in config['Peers']:
config['Peers']['peer_MTU'] = "1420"
if 'peer_keep_alive' not in config['Peers']:
config['Peers']['peer_keep_alive'] = "21"
config.write(open(dashboard_conf, "w")) config.write(open(dashboard_conf, "w"))
config.clear() config.clear()
"""
Dashboard check update
"""
def check_update(): def check_update():
conf = configparser.ConfigParser(strict=False) conf = configparser.ConfigParser(strict=False)
conf.read(dashboard_conf) conf.read(dashboard_conf)

View File

@ -194,15 +194,30 @@ main{
margin-bottom: 3rem; margin-bottom: 3rem;
} }
/*.add_btn{*/ .peer_list{
/* position: fixed;*/ margin-bottom: 7rem
/* bottom: 1.75rem;*/ }
/* right: 1.75rem;*/
/* z-index: 1000;*/ @media (max-width: 768px) {
/* padding: 0.75rem 1.5rem;*/ .add_btn{
/* border-radius: 3rem;*/ bottom: 1.5rem !important;
/* font-size: 1rem;*/ }
/*}*/
.peer_list{
margin-bottom: 4rem !important;
}
}
.add_btn{
position: fixed;
bottom: 3rem;
right: 2rem;
z-index: 99;
border-radius: 100px;
padding: 10px 20px;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
}
@-webkit-keyframes rotating /* Safari and Chrome */ { @-webkit-keyframes rotating /* Safari and Chrome */ {
from { from {

View File

@ -17,7 +17,6 @@ function generate_key(){
$("#re_generate_key i").removeClass("rotating") $("#re_generate_key i").removeClass("rotating")
}) })
} }
function generate_public_key(){ function generate_public_key(){
$.ajax({ $.ajax({
"url": "/generate_public_key", "url": "/generate_public_key",
@ -26,7 +25,7 @@ function generate_public_key(){
"data": JSON.stringify({"private_key": $("#private_key").val()}) "data": JSON.stringify({"private_key": $("#private_key").val()})
}).done(function(res){ }).done(function(res){
if(res['status'] === "failed"){ if(res['status'] === "failed"){
$("#add_peer_alert").html(res['msg']+$("#add_peer_alert").html()); $("#add_peer_alert").html(res['msg']);
$("#add_peer_alert").removeClass("d-none"); $("#add_peer_alert").removeClass("d-none");
}else{ }else{
$("#add_peer_alert").addClass("d-none"); $("#add_peer_alert").addClass("d-none");
@ -46,24 +45,21 @@ $("#private_key").change(function(){
$("#public_key").val("") $("#public_key").val("")
} }
}) })
$('#add_modal').on('show.bs.modal', function (event) { $('#add_modal').on('show.bs.modal', function (event) {
generate_key() generate_key()
}) })
$("#re_generate_key").click(function (){ $("#re_generate_key").click(function (){
$("#public_key").attr("disabled","disabled") $("#public_key").attr("disabled","disabled")
$("#re_generate_key i").addClass("rotating") $("#re_generate_key i").addClass("rotating")
generate_key() generate_key()
}) })
$("#save_peer").click(function(){ $("#save_peer").click(function(){
$(this).attr("disabled","disabled") $(this).attr("disabled","disabled")
$(this).html("Saving...") $(this).html("Saving...")
if ($("#allowed_ips").val() !== "" && $("#public_key").val() !== "" && $("#new_add_DNS").val() !== "" && $("#new_add_endpoint_allowed_ip").val() != ""){ if ($("#allowed_ips").val() !== "" && $("#public_key").val() !== "" && $("#new_add_DNS").val() !== "" && $("#new_add_endpoint_allowed_ip").val() != ""){
var conf = $(this).attr('conf_id') var conf = $(this).attr('conf_id')
var data_list = [$("#private_key"), $("#allowed_ips"), $("#new_add_name"), $("#new_add_DNS"), $("#new_add_endpoint_allowed_ip")] var data_list = [$("#private_key"), $("#allowed_ips"), $("#new_add_name"), $("#new_add_DNS"), $("#new_add_endpoint_allowed_ip"),$("#new_add_MTU"),$("#new_add_keep_alive")]
for (var i = 0; i < data_list.length; i++){ for (var i = 0; i < data_list.length; i++){
data_list[i].attr("disabled", "disabled") data_list[i].attr("disabled", "disabled")
} }
@ -79,12 +75,19 @@ $("#save_peer").click(function(){
"allowed_ips": $("#allowed_ips").val(), "allowed_ips": $("#allowed_ips").val(),
"name":$("#new_add_name").val(), "name":$("#new_add_name").val(),
"DNS": $("#new_add_DNS").val(), "DNS": $("#new_add_DNS").val(),
"endpoint_allowed_ip": $("#new_add_endpoint_allowed_ip").val() "endpoint_allowed_ip": $("#new_add_endpoint_allowed_ip").val(),
"MTU": $("#new_add_MTU").val(),
"keep_alive": $("#new_add_keep_alive").val()
}), }),
success: function (response){ success: function (response){
if(response != "true"){ if(response != "true"){
$("#add_peer_alert").html(response+$("#add_peer_alert").html()); $("#add_peer_alert").html(response);
$("#add_peer_alert").removeClass("d-none"); $("#add_peer_alert").removeClass("d-none");
for (var i = 0; i < data_list.length; i++){
data_list[i].removeAttr("disabled", "disabled")
}
$("#save_peer").removeAttr("disabled")
$("#save_peer").html("Save")
} }
else{ else{
location.reload(); location.reload();
@ -164,13 +167,15 @@ $("body").on("click", ".btn-setting-peer", function(){
}, },
data: JSON.stringify({"id": peer_id}), data: JSON.stringify({"id": peer_id}),
success: function(response){ success: function(response){
let peer_name = ((response['name'] === "") ? "Untitled Peer" : response['name']); var peer_name = ((response['name'] === "") ? "Untitled Peer" : response['name'])
$("#setting_modal .peer_name").html(peer_name); $("#setting_modal .peer_name").html(peer_name);
$("#setting_modal #peer_name_textbox").val(peer_name) $("#setting_modal #peer_name_textbox").val(response['name'])
$("#setting_modal #peer_private_key_textbox").val(response['private_key']) $("#setting_modal #peer_private_key_textbox").val(response['private_key'])
$("#setting_modal #peer_DNS_textbox").val(response['DNS']) $("#setting_modal #peer_DNS_textbox").val(response['DNS'])
$("#setting_modal #peer_allowed_ip_textbox").val(response['allowed_ip']) $("#setting_modal #peer_allowed_ip_textbox").val(response['allowed_ip'])
$("#setting_modal #peer_endpoint_allowed_ips").val(response['endpoint_allowed_ip']) $("#setting_modal #peer_endpoint_allowed_ips").val(response['endpoint_allowed_ip'])
$("#setting_modal #peer_mtu").val(response['mtu'])
$("#setting_modal #peer_keep_alive").val(response['keep_alive'])
settingModal.toggle(); settingModal.toggle();
endProgressBar() endProgressBar()
} }
@ -211,7 +216,10 @@ $("#save_peer_setting").click(function (){
){ ){
var peer_id = $(this).attr("peer_id"); var peer_id = $(this).attr("peer_id");
var conf_id = $(this).attr("conf_id"); var conf_id = $(this).attr("conf_id");
var data_list = [$("#peer_name_textbox"), $("#peer_DNS_textbox"), $("#peer_private_key_textbox"), $("#peer_allowed_ip_textbox"), $("#peer_endpoint_allowed_ips")] var data_list = [
$("#peer_name_textbox"), $("#peer_DNS_textbox"), $("#peer_private_key_textbox"),
$("#peer_allowed_ip_textbox"), $("#peer_endpoint_allowed_ips"), $("#peer_mtu"), $("#peer_keep_alive")
]
for (var i = 0; i < data_list.length; i++){ for (var i = 0; i < data_list.length; i++){
data_list[i].attr("disabled", "disabled") data_list[i].attr("disabled", "disabled")
} }
@ -227,7 +235,9 @@ $("#save_peer_setting").click(function (){
DNS: $("#peer_DNS_textbox").val(), DNS: $("#peer_DNS_textbox").val(),
private_key: $("#peer_private_key_textbox").val(), private_key: $("#peer_private_key_textbox").val(),
allowed_ip: $("#peer_allowed_ip_textbox").val(), allowed_ip: $("#peer_allowed_ip_textbox").val(),
endpoint_allowed_ip: $("#peer_endpoint_allowed_ips").val() endpoint_allowed_ip: $("#peer_endpoint_allowed_ips").val(),
MTU: $("#peer_mtu").val(),
keep_alive: $("#peer_keep_alive").val()
}), }),
success: function (response){ success: function (response){
if (response['status'] === "failed"){ if (response['status'] === "failed"){
@ -279,7 +289,6 @@ function doneTyping () {
load_data($('#search_peer_textbox').val()); load_data($('#search_peer_textbox').val());
} }
// Sorting // Sorting
$("body").on("change", "#sort_by_dropdown", function (){ $("body").on("change", "#sort_by_dropdown", function (){
$.ajax({ $.ajax({
@ -293,7 +302,7 @@ $("body").on("change", "#sort_by_dropdown", function (){
}) })
}) })
// Click key to copy
$("body").on("mouseenter", ".key", function(){ $("body").on("mouseenter", ".key", function(){
var label = $(this).parent().siblings().children()[1] var label = $(this).parent().siblings().children()[1]
label.style.opacity = "100" label.style.opacity = "100"
@ -319,6 +328,7 @@ function copyToClipboard(element) {
$temp.remove(); $temp.remove();
} }
// Update Interval
$("body").on("click", ".update_interval", function(){ $("body").on("click", ".update_interval", function(){
$.ajax({ $.ajax({
method:"POST", method:"POST",
@ -333,7 +343,7 @@ $("body").on("click", ".refresh", function (){
load_data($('#search_peer_textbox').val()); load_data($('#search_peer_textbox').val());
}); });
// Switch display mode
$("body").on("click", ".display_mode", function(){ $("body").on("click", ".display_mode", function(){
$.ajax({ $.ajax({
method:"GET", method:"GET",

View File

@ -11,11 +11,7 @@
<input type="text" class="form-control" id="search_peer_textbox" placeholder="Search Peer..." value="" style="display: none"> <input type="text" class="form-control" id="search_peer_textbox" placeholder="Search Peer..." value="" style="display: none">
</div> </div>
</div> </div>
<div id="config_body"></div>
<div id="config_body">
</div>
</div> </div>
<div class="modal fade" id="add_modal" data-backdrop="static" data-keyboard="false" tabindex="-1" <div class="modal fade" id="add_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true"> aria-labelledby="staticBackdropLabel" aria-hidden="true">
@ -44,9 +40,7 @@
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control" id="private_key" aria-describedby="public_key"> <input type="text" class="form-control" id="private_key" aria-describedby="public_key">
<div class="input-group-append"> <div class="input-group-append">
<button type="button" class="btn btn-danger" id="re_generate_key"> <button type="button" class="btn btn-danger" id="re_generate_key"><i class="bi bi-arrow-repeat"></i></button>
<i class="bi bi-arrow-repeat"></i>
</button>
</div> </div>
</div> </div>
</div> </div>
@ -73,13 +67,24 @@
<input type="text" class="form-control" id="new_add_DNS" value="{{ DNS }}"> <input type="text" class="form-control" id="new_add_DNS" value="{{ DNS }}">
</div> </div>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<div class="form-group"> <div class="form-group">
<label for="new_add_endpoint_allowed_ip">Endpoint Allowed IPs <code>(Required)</code></label> <label for="new_add_endpoint_allowed_ip">Endpoint Allowed IPs <code>(Required)</code></label>
<input type="text" class="form-control" id="new_add_endpoint_allowed_ip" value="{{ endpoint_allowed_ip }}"> <input type="text" class="form-control" id="new_add_endpoint_allowed_ip" value="{{ endpoint_allowed_ip }}">
</div> </div>
</div> </div>
<div class="col-sm-6">
<div class="form-group">
<label for="new_add_MTU">MTU</label>
<input type="text" class="form-control" id="new_add_MTU" value="{{ mtu }}">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="new_add_keep_alive">Persistent keepalive</label>
<input type="text" class="form-control" id="new_add_keep_alive" value="{{ keep_alive }}">
</div>
</div>
</div> </div>
</form> </form>
</div> </div>
@ -132,29 +137,51 @@
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="mb-3"> <div>
<label for="peer_name_textbox" class="form-label">Name</label>
<input type="text" class="form-control" id="peer_name_textbox" placeholder="">
</div>
<div class="mb-3">
<label for="peer_private_key_textbox" class="form-label">Private Key <code>(Required for QR Code and download)</code></label> <label for="peer_private_key_textbox" class="form-label">Private Key <code>(Required for QR Code and download)</code></label>
<input type="password" class="form-control" id="peer_private_key_textbox" style="padding-right: 40px"> <input type="password" class="form-control" id="peer_private_key_textbox" style="padding-right: 40px">
<a class="peer_private_key_textbox_switch"><i class="bi bi-eye-fill"></i></a> <a class="peer_private_key_textbox_switch"><i class="bi bi-eye-fill"></i></a>
</div> </div>
<hr>
<div class="row">
<div class="col-sm-6">
<div class="mb-3">
<label for="peer_name_textbox" class="form-label">Name</label>
<input type="text" class="form-control" id="peer_name_textbox" placeholder="">
</div>
</div>
<div class="col-sm-6">
<div class="mb-3"> <div class="mb-3">
<label for="peer_allowed_ip_textbox" class="form-label">Allowed IPs <code>(Required)</code></label> <label for="peer_allowed_ip_textbox" class="form-label">Allowed IPs <code>(Required)</code></label>
<input type="text" class="form-control" id="peer_allowed_ip_textbox"> <input type="text" class="form-control" id="peer_allowed_ip_textbox">
</div> </div>
</div>
<div class="col-sm-6">
<div class="mb-3"> <div class="mb-3">
<label for="peer_DNS_textbox" class="form-label">DNS <code>(Required)</code></label> <label for="peer_DNS_textbox" class="form-label">DNS <code>(Required)</code></label>
<input type="text" class="form-control" id="peer_DNS_textbox"> <input type="text" class="form-control" id="peer_DNS_textbox">
</div> </div>
</div>
<div class="col-sm-6">
<div class="mb-3"> <div class="mb-3">
<label for="peer_endpoint_allowed_ips" class="form-label">Endpoint Allowed IPs <code>(Required)</code></label> <label for="peer_endpoint_allowed_ips" class="form-label">Endpoint Allowed IPs <code>(Required)</code></label>
<input type="text" class="form-control" id="peer_endpoint_allowed_ips"> <input type="text" class="form-control" id="peer_endpoint_allowed_ips">
</div> </div>
</div>
<div class="col-sm-6">
<div class="mb-3">
<label for="peer_mtu" class="form-label">MTU</label>
<input type="text" class="form-control" id="peer_mtu">
</div>
</div>
<div class="col-sm-6">
<div class="mb-3">
<label for="peer_keep_alive" class="form-label">Persistent Keepalive</label>
<input type="text" class="form-control" id="peer_keep_alive">
</div>
</div>
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
@ -223,9 +250,6 @@
},250) },250)
} }
function load_data(search){ function load_data(search){
startProgressBar() startProgressBar()
$.ajax({ $.ajax({
@ -237,10 +261,8 @@
success: function (response){ success: function (response){
$("#config_body").html(response); $("#config_body").html(response);
$("#search_peer_textbox").css("display", "block") $("#search_peer_textbox").css("display", "block")
if (bar.css("width") !== "0%"){
endProgressBar() endProgressBar()
} }
}
}) })
} }
$(document).ready(function(){ $(document).ready(function(){
@ -249,8 +271,6 @@
load_data($('#search_peer_textbox').val()); load_data($('#search_peer_textbox').val());
}, {{dashboard_refresh_interval}}) }, {{dashboard_refresh_interval}})
}); });
</script> </script>
<script src="{{ url_for('static',filename='js/configuration.js') }}"></script> <script src="{{ url_for('static',filename='js/configuration.js') }}"></script>
</html> </html>

View File

@ -1,9 +1,19 @@
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4 mb-4"> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4 mb-4">
<div class="info mt-4"> <div class="info mt-4">
{% if conf_data['listen_port'] == "" and conf_data['status'] == "stopped" %}
<div class="alert alert-warning" role="alert">
Peer QR Code and configuration file download required a specified <strong>Listen Port</strong>.
</div>
{% endif %}
{% if conf_data['conf_address'] == "N/A" %}
<div class="alert alert-warning" role="alert">
Configuration <strong>Address</strong> not be specified to have peer connect to it.
</div>
{% endif %}
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<small class="text-muted"><strong>CONFIGURATION</strong></small> <small class="text-muted"><strong>CONFIGURATION</strong></small>
<h1 class="mb-3">{{conf_data['name']}}</h1> <h1 class="mb-3"><samp>{{conf_data['name']}}</samp></h1>
</div> </div>
<div class="col"> <div class="col">
<small class="text-muted"><strong>ACTION</strong></small><br> <small class="text-muted"><strong>ACTION</strong></small><br>
@ -47,7 +57,14 @@
</div> </div>
<div class="col-sm"> <div class="col-sm">
<small class="text-muted"><strong>LISTEN PORT</strong></small> <small class="text-muted"><strong>LISTEN PORT</strong></small>
<h6 style="text-transform: uppercase;"><samp>{{conf_data['listen_port']}}</samp></h6> <h6 style="text-transform: uppercase;"><samp>
{% if conf_data['listen_port'] == "" %}
N/A
{% else %}
{{conf_data['listen_port']}}
{% endif %}
</samp></h6>
</div> </div>
<div class="col-sm"> <div class="col-sm">
<small class="text-muted"><strong>ADDRESS</strong></small> <small class="text-muted"><strong>ADDRESS</strong></small>
@ -88,20 +105,15 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm"> <button type="button" class="btn btn-primary add_btn" data-toggle="modal" data-target="#add_modal">
<div class="form-group"> <i class="bi bi-plus-circle-fill" style=""></i> Add Peer
<label><small class="text-muted">Add</small></label><br>
<button type="button" class="btn btn-primary add_btn" data-toggle="modal" data-target="#add_modal" style="width: 100%">
<i class="bi bi-plus-circle-fill"></i> Add Peer
</button> </button>
</div> </div>
</div>
</div>
<hr> <hr>
</div> </div>
</div> </div>
<div class="row"> <div class="row peer_list">
{% if conf_data['peer_data']|length == 0 %} {% if conf_data['peer_data']|length == 0 %}
<div class="col-12" style="text-align: center; margin-top: 1.5rem"> <div class="col-12" style="text-align: center; margin-top: 1.5rem">
<h3 class="text-muted">Oops! No peers found ‘︿’</h3> <h3 class="text-muted">Oops! No peers found ‘︿’</h3>
@ -112,29 +124,34 @@
{% if peer_display_mode == "list" %} {% if peer_display_mode == "list" %}
<div class="col-12"> <div class="col-12">
{% else %} {% else %}
<div class="col-sm-6 col-md-4"> <div class="col-sm-6 col-lg-4">
{% endif %} {% endif %}
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header"> <div class="card-header">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col">
<div class="card-header-body "> <div class="card-header-body ">
{% if not i['name']%} {% if not i['name']%}
{{ "Untitled Peer" }} {{ "Untitled" }}
{% else %} {% else %}
{{i['name']}} {{i['name']}}
{% endif %} {% endif %}
<span class="dot dot-{{i['status']}}"></span> {# <span class="dot dot-{{i['status']}}"></span>#}
</div> </div>
</div> </div>
<div class="col-12 peer_data_group">
<p class="text-primary" style="text-transform: uppercase; display: inline-block; margin-bottom: 0; margin-right: 1rem"><i class="bi bi-arrow-down-right"></i> {{i['total_receive']}} GB</p>
<p class="text-success" style="text-transform: uppercase; display: inline-block; margin-bottom: 0"><i class="bi bi-arrow-up-right"></i> {{i['total_sent']}} GB</p>
</div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
<div class="col-6">
<small class="text-muted"><strong>STATUS</strong></small>
<h6 style="text-transform: uppercase;" class="mb-2"><span class="dot dot-{{i['status']}}" style="margin-left: 0 !important;margin-top: 5px"></span></h6>
</div>
<div class="col-6 peer_data_group" style="text-align: right">
<small class="text-muted"><strong>TRANSFER</strong></small>
<p class="text-primary" style="text-transform: uppercase; margin-bottom: 0;"><small><i class="bi bi-arrow-down-right"></i> {{i['total_receive']}} GB</small></p>
<p class="text-success" style="text-transform: uppercase; margin-bottom: 0"><small><i class="bi bi-arrow-up-right"></i> {{i['total_sent']}} GB</small></p>
</div>
<div class="col-sm"> <div class="col-sm">
<small class="text-muted" style="display: flex"> <small class="text-muted" style="display: flex">
<strong>PEER</strong> <strong>PEER</strong>

View File

@ -1,7 +1,7 @@
<html> <html>
{% with %} {% with %}
{% set title="Settings" %} {% set title="Settings" %}
{% include "header.html"%} {% include "header.html" %}
{% endwith %} {% endwith %}
<body> <body>
{% include "navbar.html" %} {% include "navbar.html" %}
@ -14,53 +14,86 @@
{{ message }} {{ message }}
</div> </div>
{% endif %} {% endif %}
<h1 class="pb-4">Settings</h1> <h1 class="">Settings</h1>
{% if required_auth == "true" %}
<h3>Account</h3>
<form action="/update_acct" method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control mb-4" id="username" name="username"
value="{{ session['username'] }}" required>
<button type="submit" class="btn btn-success">Update Account</button>
</div>
</form>
<hr> <hr>
<h3>New Peer Default Settings</h3> {% if required_auth == "true" %}
<div class="card mb-3">
<h6 class="card-header">Peer Default Settings</h6>
<div class="card-body">
<form action="/update_peer_default_config" method="post"> <form action="/update_peer_default_config" method="post">
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<div class="col-sm"> <div class="col-sm-6">
<label for="username">DNS</label> <label for="peer_global_DNS">DNS</label>
<input type="text" class="form-control mb-4" id="peer_global_DNS" name="peer_global_DNS" <input type="text" class="form-control mb-4" id="peer_global_DNS"
name="peer_global_DNS"
value="{{ peer_global_DNS }}" required> value="{{ peer_global_DNS }}" required>
</div> </div>
<div class="col-sm"> <div class="col-sm-6">
<label for="username">Peer Endpoint Allowed IPs</label> <label for="peer_endpoint_allowed_ip">Peer Endpoint Allowed IPs</label>
<input type="text" class="form-control mb-4" id="peer_endpoint_allowed_ip" name="peer_endpoint_allowed_ip" <input type="text" class="form-control mb-4" id="peer_endpoint_allowed_ip"
name="peer_endpoint_allowed_ip"
value="{{ peer_endpoint_allowed_ip }}" required> value="{{ peer_endpoint_allowed_ip }}" required>
</div> </div>
<div class="col-sm-6">
<label for="peer_mtu">MTU</label>
<input type="text" class="form-control mb-4" id="peer_mtu"
name="peer_mtu"
value="{{ peer_mtu }}">
</div>
<div class="col-sm-6">
<label for="peer_keep_alive">Persistent Keepalive</label>
<input type="text" class="form-control mb-4" id="peer_keep_alive"
name="peer_keep_alive"
value="{{ peer_keepalive }}">
</div>
<div class="col-sm-12">
<label for="peer_remote_endpoint"><strong>Peer Remote Endpoint (This will be change globally, and will be apply to all peer's QR code and configuration file.)</strong></label>
<input type="text" class="form-control mb-4" id="peer_remote_endpoint"
name="peer_remote_endpoint"
value="{{ peer_remote_endpoint }}" required>
</div>
</div> </div>
<button class="btn btn-success" type="submit">Update Peer Default Settings</button> <button class="btn btn-success" type="submit">Update Peer Default Settings</button>
</div> </div>
</form> </form>
</div>
</div>
<hr> <hr>
<div class="card mb-3">
<h6 class="card-header">WireGuard Configuration Path</h6>
<h3>WireGuard Configuration Path</h3> <div class="card-body">
<form action="/update_wg_conf_path" method="post" class="update_wg_conf_path"> <form action="/update_wg_conf_path" method="post" class="update_wg_conf_path">
<div class="form-group"> <div class="form-group">
<label for="username">Path</label> <label for="wg_conf_path">Path</label>
<input type="text" class="form-control mb-4" id="wg_conf_path" name="wg_conf_path" <input type="text" class="form-control mb-2" id="wg_conf_path" name="wg_conf_path"
value="{{ wg_conf_path }}"> value="{{ wg_conf_path }}">
<p>Remember to remove <code>/</code> at the end of your path. e.g <code>/etc/wireguard</code> <p class="text-muted">Remember to remove <code>/</code> at the end of your path. e.g <code>/etc/wireguard</code>
</p> </p>
<button class="btn btn-danger change_path">Update Path & Restart Dashboard</button> <button class="btn btn-danger change_path">Update Path & Restart Dashboard</button>
</div> </div>
</form> </form>
<hr> </div>
<h3>Security</h3> </div>
<form action="/update_pwd" , method="post">
<div class="card mb-3">
<h6 class="card-header">Account</h6>
<div class="card-body">
<form action="/update_acct" method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control mb-4" id="username" name="username"
value="{{ session['username'] }}" required>
<button type="submit" class="btn btn-danger">Update Account</button>
</div>
</form>
</div>
</div>
<div class="card mb-3">
<h6 class="card-header">Security</h6>
<div class="card-body">
<form action="/update_pwd" method="post">
<div class="form-group"> <div class="form-group">
<label for="currentpass">Current Password</label> <label for="currentpass">Current Password</label>
<input type="password" class="form-control mb-2" id="currentpass" name="currentpass"> <input type="password" class="form-control mb-2" id="currentpass" name="currentpass">
@ -71,9 +104,12 @@
<button type="submit" class="btn btn-danger">Update Password</button> <button type="submit" class="btn btn-danger">Update Password</button>
</div> </div>
</form> </form>
<hr> </div>
</div>
{% endif %} {% endif %}
<h3>Dashboard Configuration</h3> <div class="card">
<h6 class="card-header">Dashboard Configuration</h6>
<div class="card-body">
<form action="/update_app_ip_port" method="post" class="update_app_ip_port"> <form action="/update_app_ip_port" method="post" class="update_app_ip_port">
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@ -90,11 +126,13 @@
</div> </div>
</div> </div>
<button type="button" class="btn btn-danger confirm_modal" data-toggle="modal" <button type="button" class="btn btn-danger confirm_modal" data-toggle="modal"
data-target="#confirmModal">Update Configuration & Restart data-target="#confirmModal">Update Configuration & Restart Dashboard
</button> </button>
</div> </div>
</form> </form>
</div> </div>
</div>
</div>
</main> </main>
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="confirmModal" data-backdrop="static" data-keyboard="false" tabindex="-1" <div class="modal fade" id="confirmModal" data-backdrop="static" data-keyboard="false" tabindex="-1"

View File

@ -19,7 +19,7 @@
</h6> </h6>
<ul class="nav flex-column"> <ul class="nav flex-column">
{% for i in conf%} {% for i in conf%}
<li class="nav-item"><a class="nav-link sb-{{i['conf']}}-url" href="/configuration/{{i['conf']}}">{{i['conf']}}</a></li> <li class="nav-item"><a class="nav-link sb-{{i['conf']}}-url" href="/configuration/{{i['conf']}}"><samp>{{i['conf']}}</samp></a></li>
{%endfor%} {%endfor%}
</ul> </ul>
<hr> <hr>

View File

@ -36,4 +36,9 @@
</div> </div>
</body> </body>
{% include "footer.html" %} {% include "footer.html" %}
<script>
$("button").click(function(){
$(this).html("Signing In...")
})
</script>
</html> </html>

View File

@ -5,17 +5,19 @@ app_official_name="Wireguard Dashboard"
dashes='------------------------------------------------------------' dashes='------------------------------------------------------------'
equals='============================================================' equals='============================================================'
help () { help () {
printf "<Wireguard Dashboard> by Donald Zou - https://github.com/donaldzou \n" printf "=================================================================================\n"
printf "Usage: ./wgd.sh <option>" printf "+ <Wireguard Dashboard> by Donald Zou - https://github.com/donaldzou +\n"
printf "\n \n" printf "=================================================================================\n"
printf "Available options: \n" printf "| Usage: ./wgd.sh <option> |\n"
printf " start: To start "app_official_name".\n" printf "| |\n"
printf " stop: To stop "app_official_name".\n" printf "| Available options: |\n"
printf " debug: To start "app_official_name" in debug mode (i.e run in foreground).\n" printf "| start: To start Wireguard Dashboard |\n"
printf " update: To update "app_official_name" to the newest version from GitHub.\n" printf "| stop: To stop Wireguard Dashboard. |\n"
printf " install: To install "app_official_name".\n" printf "| debug: To start Wireguard Dashboard in debug mode (i.e run in foreground). |\n"
printf "Thank you for using! Your support is my motivation ;) \n" printf "| update: To update Wireguard Dashboard to the newest version from GitHub. |\n"
printf "\n" printf "| install: To install Wireguard Dashboard. |\n"
printf "| Thank you for using! Your support is my motivation ;) |\n"
printf "=================================================================================\n"
} }
install_wgd(){ install_wgd(){
@ -122,9 +124,10 @@ if [ "$#" != 1 ];
install_wgd install_wgd
elif [ "$1" = "restart" ]; then elif [ "$1" = "restart" ]; then
if check_wgd_status; then if check_wgd_status; then
printf "%s\n" "$dashes"
stop_wgd stop_wgd
sleep 2
printf "| Wireguard Dashboard is stopped. |\n" printf "| Wireguard Dashboard is stopped. |\n"
sleep 2
start_wgd start_wgd
else else
start_wgd start_wgd