mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-08-27 23:41:14 +00:00
v2.2-beta4
Finished testing the QR code function and finish debugging the peer file download function.
This commit is contained in:
185
src/dashboard.py
185
src/dashboard.py
@@ -18,7 +18,7 @@ from tinydb import TinyDB, Query
|
||||
from icmplib import ping, multiping, traceroute, resolve, Host, Hop
|
||||
|
||||
# Dashboard Version
|
||||
dashboard_version = 'v2.1'
|
||||
dashboard_version = 'v2.2'
|
||||
# Dashboard Config Name
|
||||
dashboard_conf = 'wg-dashboard.ini'
|
||||
# Default Wireguard IP
|
||||
@@ -186,6 +186,7 @@ def get_conf_peers_data(config_name):
|
||||
db.insert({
|
||||
"id": i['PublicKey'],
|
||||
"private_key": "",
|
||||
"DNS":"1.1.1.1",
|
||||
"name": "",
|
||||
"total_receive": 0,
|
||||
"total_sent": 0,
|
||||
@@ -198,8 +199,12 @@ def get_conf_peers_data(config_name):
|
||||
})
|
||||
else:
|
||||
# Update database since V2.2
|
||||
update_db = {}
|
||||
if "private_key" not in search[0]:
|
||||
db.update({'private_key':''}, peers.id == i['PublicKey'])
|
||||
update_db['private_key'] = ''
|
||||
if "DNS" not in search[0]:
|
||||
update_db['DNS'] = '1.1.1.1'
|
||||
db.update(update_db, peers.id == i['PublicKey'])
|
||||
|
||||
tic = time.perf_counter()
|
||||
get_latest_handshake(config_name, db, peers)
|
||||
@@ -271,6 +276,61 @@ def get_conf_list():
|
||||
conf = sorted(conf, key=itemgetter('conf'))
|
||||
return conf
|
||||
|
||||
def genKeys():
|
||||
gen = subprocess.check_output('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt',
|
||||
shell=True)
|
||||
private = open('private_key.txt')
|
||||
private_key = private.readline().strip()
|
||||
public = open('public_key.txt')
|
||||
public_key = public.readline().strip()
|
||||
data = {"private_key": private_key, "public_key": public_key}
|
||||
private.close()
|
||||
public.close()
|
||||
os.remove('private_key.txt')
|
||||
os.remove('public_key.txt')
|
||||
return data
|
||||
|
||||
def genPubKey(private_key):
|
||||
pri_key_file = open('private_key.txt', 'w')
|
||||
pri_key_file.write(private_key)
|
||||
pri_key_file.close()
|
||||
try:
|
||||
check = subprocess.check_output("wg pubkey < private_key.txt > public_key.txt", shell=True)
|
||||
public = open('public_key.txt')
|
||||
public_key = public.readline().strip()
|
||||
os.remove('private_key.txt')
|
||||
os.remove('public_key.txt')
|
||||
return {"status":'success', "msg":"", "data":public_key}
|
||||
except subprocess.CalledProcessError as exc:
|
||||
os.remove('private_key.txt')
|
||||
return {"status":'failed', "msg":"Key is not the correct length or format", "data":""}
|
||||
|
||||
def checkKeyMatch(private_key, public_key, config_name):
|
||||
result = genPubKey(private_key)
|
||||
if result['status'] == 'failed':
|
||||
return result
|
||||
else:
|
||||
db = TinyDB('db/' + config_name + '.json')
|
||||
peers = Query()
|
||||
match = db.search(peers.id == result['data'])
|
||||
if len(match) != 1 or result['data'] != public_key:
|
||||
return {'status': 'failed', 'msg': 'Please check your private key, it does not match with the public key.'}
|
||||
else:
|
||||
return {'status': 'success'}
|
||||
|
||||
def checkAllowedIP(public_key, ip, config_name):
|
||||
db = TinyDB('db/' + config_name + '.json')
|
||||
peers = Query()
|
||||
peer = db.search(peers.id == public_key)
|
||||
if len(peer) != 1:
|
||||
return {'status': 'failed', 'msg': 'Peer does not exist'}
|
||||
else:
|
||||
existed_ip = db.search((peers.id != public_key) & (peers.allowed_ip == ip))
|
||||
if len(existed_ip) != 0:
|
||||
return {'status':'failed', 'msg':"Allowed IP already taken by another peer."}
|
||||
else:
|
||||
return {'status':'success'}
|
||||
|
||||
@app.before_request
|
||||
def auth_req():
|
||||
conf = configparser.ConfigParser(strict=False)
|
||||
@@ -285,7 +345,10 @@ def auth_req():
|
||||
request.endpoint != "auth" and \
|
||||
"username" not in session:
|
||||
print("User not loggedin - Attemped access: "+str(request.endpoint))
|
||||
session['message'] = "You need to sign in first!"
|
||||
if request.endpoint != "index":
|
||||
session['message'] = "You need to sign in first!"
|
||||
else:
|
||||
session['message'] = ""
|
||||
return redirect(url_for("signin"))
|
||||
else:
|
||||
if request.endpoint in ['signin', 'signout', 'auth', 'settings', 'update_acct', 'update_pwd',
|
||||
@@ -509,6 +572,7 @@ def get_conf(config_name):
|
||||
"public_key": get_conf_pub_key(config_name),
|
||||
"listen_port": get_conf_listen_port(config_name),
|
||||
"running_peer": get_conf_running_peer_number(config_name),
|
||||
|
||||
}
|
||||
if conf_data['status'] == "stopped":
|
||||
# return redirect('/')
|
||||
@@ -540,6 +604,8 @@ def switch(config_name):
|
||||
|
||||
@app.route('/add_peer/<config_name>', methods=['POST'])
|
||||
def add_peer(config_name):
|
||||
db = TinyDB("db/" + config_name + ".json")
|
||||
peers = Query()
|
||||
data = request.get_json()
|
||||
public_key = data['public_key']
|
||||
allowed_ips = data['allowed_ips']
|
||||
@@ -548,6 +614,8 @@ def add_peer(config_name):
|
||||
return config_name+" is not running."
|
||||
if public_key in keys:
|
||||
return "Public key already exist."
|
||||
if len(db.search(peers.allowed_ip.matches(allowed_ips))) != 0:
|
||||
return "Allowed IP already taken by another peer."
|
||||
else:
|
||||
status = ""
|
||||
try:
|
||||
@@ -555,12 +623,11 @@ def add_peer(config_name):
|
||||
"wg set " + config_name + " peer " + public_key + " allowed-ips " + allowed_ips, shell=True, stderr=subprocess.STDOUT)
|
||||
status = subprocess.check_output("wg-quick save " + config_name, shell=True, stderr=subprocess.STDOUT)
|
||||
get_conf_peers_data(config_name)
|
||||
db = TinyDB("db/" + config_name + ".json")
|
||||
peers = Query()
|
||||
db.update({"name": data['name'], "private_key": data['private_key']}, peers.id == public_key)
|
||||
db.update({"name": data['name'], "private_key": data['private_key'], "DNS": data['DNS']}, peers.id == public_key)
|
||||
db.close()
|
||||
return "true"
|
||||
except subprocess.CalledProcessError as exc:
|
||||
db.close()
|
||||
return exc.output.strip()
|
||||
|
||||
|
||||
@@ -590,19 +657,47 @@ def remove_peer(config_name):
|
||||
return exc.output.strip()
|
||||
|
||||
|
||||
@app.route('/save_peer_name/<config_name>', methods=['POST'])
|
||||
def save_peer_name(config_name):
|
||||
@app.route('/save_peer_setting/<config_name>', methods=['POST'])
|
||||
def save_peer_setting(config_name):
|
||||
data = request.get_json()
|
||||
id = data['id']
|
||||
name = data['name']
|
||||
private_key = data['private_key']
|
||||
DNS = data['DNS']
|
||||
allowed_ip = data['allowed_ip']
|
||||
db = TinyDB("db/" + config_name + ".json")
|
||||
peers = Query()
|
||||
db.update({"name": name}, peers.id == id)
|
||||
db.close()
|
||||
return id + " " + name
|
||||
if len(db.search(peers.id == id)) == 1:
|
||||
check_ip = checkAllowedIP(id, allowed_ip, config_name)
|
||||
if private_key != "":
|
||||
check_key = checkKeyMatch(private_key, id, config_name)
|
||||
if check_key['status'] == "failed":
|
||||
return jsonify(check_key)
|
||||
if check_ip['status'] == "failed":
|
||||
return jsonify(check_ip)
|
||||
|
||||
try:
|
||||
if allowed_ip == "":
|
||||
allowed_ip = '""'
|
||||
change_ip = subprocess.check_output('wg set '+config_name+" peer "+id+" allowed-ips "+allowed_ip, shell=True, stderr=subprocess.STDOUT)
|
||||
save_change_ip = subprocess.check_output('wg-quick save '+ config_name, shell=True,stderr=subprocess.STDOUT)
|
||||
if change_ip.decode("UTF-8") != "":
|
||||
return jsonify({"status":"failed", "msg": change_ip.decode("UTF-8")})
|
||||
|
||||
db.update({"name": name, "private_key": private_key, "DNS": DNS}, peers.id == id)
|
||||
db.close()
|
||||
return jsonify({"status": "success", "msg": ""})
|
||||
except subprocess.CalledProcessError as exc:
|
||||
return jsonify({"status":"failed", "msg": str(exc.output.decode("UTF-8").strip())})
|
||||
|
||||
|
||||
@app.route('/get_peer_name/<config_name>', methods=['POST'])
|
||||
|
||||
|
||||
else:
|
||||
return jsonify({"status":"failed","msg":"This peer does not exist."})
|
||||
|
||||
|
||||
@app.route('/get_peer_data/<config_name>', methods=['POST'])
|
||||
def get_peer_name(config_name):
|
||||
data = request.get_json()
|
||||
id = data['id']
|
||||
@@ -610,39 +705,55 @@ def get_peer_name(config_name):
|
||||
peers = Query()
|
||||
result = db.search(peers.id == id)
|
||||
db.close()
|
||||
return result[0]['name']
|
||||
data = {"name": result[0]['name'], "allowed_ip":result[0]['allowed_ip'], "DNS": result[0]['DNS'], "private_key": result[0]['private_key']}
|
||||
return jsonify(data)
|
||||
|
||||
@app.route('/generate_peer', methods=['GET'])
|
||||
def generate_peer():
|
||||
gen = subprocess.check_output('wg genkey > private_key.txt && wg pubkey < private_key.txt > public_key.txt',shell=True)
|
||||
private = open('private_key.txt')
|
||||
private_key = private.readline().strip()
|
||||
public = open('public_key.txt')
|
||||
public_key = public.readline().strip()
|
||||
data = {"private_key": private_key, "public_key": public_key}
|
||||
private.close()
|
||||
public.close()
|
||||
os.remove('private_key.txt')
|
||||
os.remove('public_key.txt')
|
||||
return jsonify(data)
|
||||
return jsonify(genKeys())
|
||||
|
||||
@app.route('/generate_public_key', methods=['POST'])
|
||||
def generate_public_key():
|
||||
data = request.get_json()
|
||||
private_key = data['private_key']
|
||||
pri_key_file = open('private_key.txt', 'w')
|
||||
pri_key_file.write(private_key)
|
||||
pri_key_file.close()
|
||||
try:
|
||||
check = subprocess.check_output("wg pubkey < private_key.txt > public_key.txt", shell=True)
|
||||
public = open('public_key.txt')
|
||||
public_key = public.readline().strip()
|
||||
os.remove('private_key.txt')
|
||||
os.remove('public_key.txt')
|
||||
return jsonify({"status":'success', "msg":"", "data":public_key})
|
||||
except subprocess.CalledProcessError as exc:
|
||||
os.remove('private_key.txt')
|
||||
return jsonify({"status":'failed', "msg":"Key is not the correct length or format", "data":""})
|
||||
return jsonify(genPubKey(private_key))
|
||||
|
||||
@app.route('/check_key_match/<config_name>', methods=['POST'])
|
||||
def check_key_match(config_name):
|
||||
data = request.get_json()
|
||||
private_key = data['private_key']
|
||||
public_key = data['public_key']
|
||||
return jsonify(checkKeyMatch(private_key,public_key, config_name))
|
||||
|
||||
@app.route('/download/<config_name>', methods=['GET'])
|
||||
def download(config_name):
|
||||
id = request.args.get('id')
|
||||
db = TinyDB("db/" + config_name + ".json")
|
||||
peers = Query()
|
||||
print(id)
|
||||
get_peer = db.search(peers.id == id)
|
||||
print(get_peer)
|
||||
if len(get_peer) == 1:
|
||||
peer = get_peer[0]
|
||||
if peer['private_key'] != "":
|
||||
public_key = get_conf_pub_key(config_name)
|
||||
listen_port = get_conf_listen_port(config_name)
|
||||
endpoint = wg_ip+":"+listen_port
|
||||
private_key = peer['private_key']
|
||||
allowed_ip = peer['allowed_ip']
|
||||
DNS = peer['DNS']
|
||||
name = "".join(peer['name'].split(' '))
|
||||
if name == "": name = public_key
|
||||
def generate(private_key, allowed_ip, DNS, public_key, endpoint):
|
||||
yield "[Interface]\nPrivateKey = "+private_key+"\nAddress = "+allowed_ip+"\nDNS = "+DNS+"\n\n[Peer]\nPublicKey = "+public_key+"\nAllowedIPs = 0.0.0.0/0\nEndpoint = "+endpoint
|
||||
|
||||
return app.response_class(generate(private_key,allowed_ip,DNS, public_key,endpoint), mimetype='text/conf', headers={"Content-Disposition":"attachment;filename="+name+".conf"})
|
||||
else:
|
||||
return redirect("/configuration/" + config_name)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def init_dashboard():
|
||||
# Set Default INI File
|
||||
|
@@ -1,4 +1,5 @@
|
||||
Flask==1.1.2
|
||||
tinydb==4.3.0
|
||||
ifcfg==0.21
|
||||
icmplib==2.1.1
|
||||
icmplib==2.1.1
|
||||
flask-qrcode==3.0.0
|
228
src/static/configuration.js
Normal file
228
src/static/configuration.js
Normal file
@@ -0,0 +1,228 @@
|
||||
// Config Toggle
|
||||
$("body").on("click", ".switch", function (){
|
||||
$(this).siblings($(".spinner-border")).css("display", "inline-block");
|
||||
$(this).remove()
|
||||
location.replace("/switch/"+$(this).attr('id'));
|
||||
})
|
||||
|
||||
// Generating Keys
|
||||
function generate_key(){
|
||||
$.ajax({
|
||||
"url": "/generate_peer",
|
||||
"method": "GET",
|
||||
}).done(function(res){
|
||||
$("#private_key").val(res.private_key)
|
||||
$("#public_key").val(res.public_key)
|
||||
$("#add_peer_alert").addClass("d-none");
|
||||
$("#re_generate_key i").removeClass("rotating")
|
||||
})
|
||||
}
|
||||
|
||||
function generate_public_key(){
|
||||
$.ajax({
|
||||
"url": "/generate_public_key",
|
||||
"method": "POST",
|
||||
"headers":{"Content-Type": "application/json"},
|
||||
"data": JSON.stringify({"private_key": $("#private_key").val()})
|
||||
}).done(function(res){
|
||||
if(res['status'] === "failed"){
|
||||
$("#add_peer_alert").html(res['msg']+$("#add_peer_alert").html());
|
||||
$("#add_peer_alert").removeClass("d-none");
|
||||
}else{
|
||||
$("#add_peer_alert").addClass("d-none");
|
||||
}
|
||||
$("#public_key").val(res['data'])
|
||||
$("#re_generate_key i").removeClass("rotating")
|
||||
})
|
||||
}
|
||||
|
||||
// Add Peer
|
||||
$("#private_key").change(function(){
|
||||
if ($("#private_key").val().length > 0){
|
||||
$("#re_generate_key i").addClass("rotating")
|
||||
generate_public_key()
|
||||
}else{
|
||||
$("#public_key").removeAttr("disabled")
|
||||
$("#public_key").val("")
|
||||
}
|
||||
})
|
||||
|
||||
$('#add_modal').on('show.bs.modal', function (event) {
|
||||
generate_key()
|
||||
})
|
||||
|
||||
$("#re_generate_key").click(function (){
|
||||
$("#public_key").attr("disabled","disabled")
|
||||
$("#re_generate_key i").addClass("rotating")
|
||||
generate_key()
|
||||
})
|
||||
|
||||
$("#save_peer").click(function(){
|
||||
if ($("#allowed_ips") !== "" && $("#public_key") !== ""){
|
||||
var conf = $(this).attr('conf_id')
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/add_peer/"+conf,
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({
|
||||
"private_key":$("#private_key").val(),
|
||||
"public_key":$("#public_key").val(),
|
||||
"allowed_ips": $("#allowed_ips").val(),
|
||||
"name":$("#new_add_name").val(),
|
||||
"DNS": $("#DNS").val()
|
||||
}),
|
||||
success: function (response){
|
||||
if(response != "true"){
|
||||
$("#add_peer_alert").html(response+$("#add_peer_alert").html());
|
||||
$("#add_peer_alert").removeClass("d-none");
|
||||
}
|
||||
else{
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
var qrcodeModal = new bootstrap.Modal(document.getElementById('qrcode_modal'), {
|
||||
keyboard: false
|
||||
})
|
||||
|
||||
// QR Code
|
||||
$("body").on("click", ".btn-qrcode-peer", function (){
|
||||
qrcodeModal.toggle();
|
||||
$("#qrcode_img").attr('src', $(this).attr('img_src'))
|
||||
})
|
||||
|
||||
// Delete Peer Modal
|
||||
var deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), {
|
||||
keyboard: false
|
||||
});
|
||||
|
||||
$("body").on("click", ".btn-delete-peer", function(){
|
||||
var peer_id = $(this).attr("id");
|
||||
$("#delete_peer").attr("peer_id", peer_id);
|
||||
deleteModal.toggle();
|
||||
})
|
||||
|
||||
$("#delete_peer").click(function(){
|
||||
var peer_id = $(this).attr("peer_id");
|
||||
var config = $(this).attr("conf_id");
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/remove_peer/"+config,
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({"action": "delete", "peer_id": peer_id}),
|
||||
success: function (response){
|
||||
if(response !== "true"){
|
||||
$("#remove_peer_alert").html(response+$("#add_peer_alert").html());
|
||||
$("#remove_peer_alert").removeClass("d-none");
|
||||
}
|
||||
else{
|
||||
deleteModal.toggle();
|
||||
load_data();
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html("Peer deleted!");
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Peer Setting Modal
|
||||
var settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), {
|
||||
keyboard: false
|
||||
})
|
||||
$("body").on("click", ".btn-setting-peer", function(){
|
||||
settingModal.toggle();
|
||||
var peer_id = $(this).attr("id");
|
||||
$("#save_peer_setting").attr("peer_id", peer_id);
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/get_peer_data/"+$("#setting_modal").attr("conf_id"),
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({"id": peer_id}),
|
||||
success: function(response){
|
||||
let peer_name = ((response['name'] === "") ? "Untitled Peer" : response['name']);
|
||||
$("#setting_modal .peer_name").html(peer_name);
|
||||
$("#setting_modal #peer_name_textbox").val(peer_name)
|
||||
$("#setting_modal #peer_private_key_textbox").val(response['private_key'])
|
||||
$("#setting_modal #peer_DNS_textbox").val(response['DNS'])
|
||||
$("#setting_modal #peer_allowed_ip_textbox").val(response['allowed_ip'])
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$('#setting_modal').on('hidden.bs.modal', function (event) {
|
||||
$("#setting_peer_alert").addClass("d-none");
|
||||
})
|
||||
|
||||
$("#peer_private_key_textbox").change(function(){
|
||||
if ($(this).val().length > 0){
|
||||
$.ajax({
|
||||
"url": "/check_key_match/"+$("#save_peer_setting").attr("conf_id"),
|
||||
"method": "POST",
|
||||
"headers":{"Content-Type": "application/json"},
|
||||
"data": JSON.stringify({
|
||||
"private_key": $("#peer_private_key_textbox").val(),
|
||||
"public_key": $("#save_peer_setting").attr("peer_id")
|
||||
})
|
||||
}).done(function(res){
|
||||
if(res['status'] == "failed"){
|
||||
$("#setting_peer_alert").html(res['msg']);
|
||||
$("#setting_peer_alert").removeClass("d-none");
|
||||
}else{
|
||||
$("#setting_peer_alert").addClass("d-none");
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
$("#save_peer_setting").click(function (){
|
||||
$(this).attr("disabled","disabled")
|
||||
$(this).html("Saving...")
|
||||
if ($("#peer_DNS_textbox").val() !== "" && $("#peer_allowed_ip_textbox").val() !== ""){
|
||||
var peer_id = $(this).attr("peer_id");
|
||||
var conf_id = $(this).attr("conf_id");
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/save_peer_setting/"+conf_id,
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({
|
||||
id: peer_id,
|
||||
name: $("#peer_name_textbox").val(),
|
||||
DNS: $("#peer_DNS_textbox").val(),
|
||||
private_key: $("#peer_private_key_textbox").val(),
|
||||
allowed_ip: $("#peer_allowed_ip_textbox").val()
|
||||
}),
|
||||
success: function (response){
|
||||
if (response['status'] === "failed"){
|
||||
$("#setting_peer_alert").html(response['msg']);
|
||||
$("#setting_peer_alert").removeClass("d-none");
|
||||
}else{
|
||||
settingModal.toggle();
|
||||
load_data();
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html("Peer Saved!");
|
||||
}
|
||||
$("#save_peer_setting").removeAttr("disabled")
|
||||
$("#save_peer_setting").html("Save")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
$(".peer_private_key_textbox_switch").click(function (){
|
||||
let mode = (($("#peer_private_key_textbox").attr('type') === 'password') ? "text":"password")
|
||||
let icon = (($("#peer_private_key_textbox").attr('type') === 'password') ? "bi bi-eye-slash-fill":"bi bi-eye-fill")
|
||||
$("#peer_private_key_textbox").attr('type',mode)
|
||||
$(".peer_private_key_textbox_switch i").removeClass().addClass(icon)
|
||||
})
|
@@ -130,8 +130,11 @@ body {
|
||||
|
||||
.btn-control{
|
||||
border: none !important;
|
||||
padding: 0;
|
||||
padding-right: 0.5rem;
|
||||
padding: 0 1rem 0 0;
|
||||
}
|
||||
|
||||
.share_peer_btn_group .btn-control{
|
||||
padding: 0 0 0 1rem;
|
||||
}
|
||||
|
||||
.btn-control:hover{
|
||||
@@ -146,6 +149,10 @@ body {
|
||||
color:#007bff
|
||||
}
|
||||
|
||||
.btn-download-peer:hover{
|
||||
color: #17a2b8;
|
||||
}
|
||||
|
||||
.login-container{
|
||||
padding: 2rem;
|
||||
}
|
||||
@@ -231,4 +238,12 @@ main{
|
||||
-ms-animation: rotating 0.75s linear infinite;
|
||||
-o-animation: rotating 0.75s linear infinite;
|
||||
animation: rotating 0.75s linear infinite;
|
||||
}
|
||||
|
||||
.peer_private_key_textbox_switch{
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
transform: translateY(-28px);
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
}
|
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="modal fade" id="add_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
|
||||
aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Add a new peer</h5>
|
||||
@@ -25,32 +25,44 @@
|
||||
<form id="add_peer_form">
|
||||
<div class="alert alert-warning" role="alert" style="font-size: 0.8rem">
|
||||
To generate QR code for this new peer, you need to provide the private key, or use the generated key. If you don't need the QR code, simply remove the private key and insert your existed public key.
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<label for="private_key">Private Key</label>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label for="private_key">Private Key</label>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="private_key" aria-describedby="public_key">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-danger" id="re_generate_key">
|
||||
<i class="bi bi-arrow-repeat"></i>
|
||||
</button>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="private_key" aria-describedby="public_key">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-danger" id="re_generate_key">
|
||||
<i class="bi bi-arrow-repeat"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="public_key">Public Key <code>(Required)</code></label>
|
||||
<input type="text" class="form-control" id="public_key" aria-describedby="public_key" disabled>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="allowed_ips">Allowed IPs <code>(Required)</code></label>
|
||||
<input type="text" class="form-control" id="allowed_ips">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_add_name">Name</label>
|
||||
<input type="text" class="form-control" id="new_add_name">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="allowed_ips">Allowed IPs <code>(Required)</code></label>
|
||||
<input type="text" class="form-control" id="allowed_ips">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="DNS">DNS</label>
|
||||
<input type="text" class="form-control" id="DNS" value="1.1.1.1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label for="new_add_name">Name</label>
|
||||
<input type="text" class="form-control" id="new_add_name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -88,7 +100,7 @@
|
||||
|
||||
<div class="modal fade" id="setting_modal" data-backdrop="static" data-keyboard="false" tabindex="-1"
|
||||
aria-labelledby="staticBackdropLabel" aria-hidden="true" conf_id={{conf_data['name']}} peer_id="">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="peer_name"></h5>
|
||||
@@ -97,15 +109,33 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="setting_peer_alert" class="alert alert-danger alert-dismissible fade show d-none" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</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>
|
||||
<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>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<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">
|
||||
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="peer_DNS_textbox" class="form-label">DNS <code>(Required)</code></label>
|
||||
<input type="text" class="form-control" id="peer_DNS_textbox">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="peer_name" class="form-label">Name</label>
|
||||
<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="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="save_peer_name" conf_id={{conf_data['name']}} peer_id="">Save</button>
|
||||
<button type="button" class="btn btn-primary" id="save_peer_setting" conf_id={{conf_data['name']}} peer_id="">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,180 +210,5 @@
|
||||
load_data();
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
function generate_key(){
|
||||
$.ajax({
|
||||
"url": "/generate_peer",
|
||||
"method": "GET",
|
||||
}).done(function(res){
|
||||
$("#private_key").val(res.private_key)
|
||||
$("#public_key").val(res.public_key)
|
||||
$("#add_peer_alert").addClass("d-none");
|
||||
$("#re_generate_key i").removeClass("rotating")
|
||||
})
|
||||
}
|
||||
function generate_public_key(){
|
||||
$.ajax({
|
||||
"url": "/generate_public_key",
|
||||
"method": "POST",
|
||||
"headers":{"Content-Type": "application/json"},
|
||||
"data": JSON.stringify({"private_key": $("#private_key").val()})
|
||||
}).done(function(res){
|
||||
if(res['status'] === "failed"){
|
||||
$("#add_peer_alert").html(res['msg']+$("#add_peer_alert").html());
|
||||
$("#add_peer_alert").removeClass("d-none");
|
||||
}else{
|
||||
$("#add_peer_alert").addClass("d-none");
|
||||
}
|
||||
$("#public_key").val(res['data'])
|
||||
$("#re_generate_key i").removeClass("rotating")
|
||||
})
|
||||
}
|
||||
|
||||
$("#private_key").change(function(){
|
||||
if ($("#private_key").val().length > 0){
|
||||
$("#re_generate_key i").addClass("rotating")
|
||||
generate_public_key()
|
||||
}else{
|
||||
$("#public_key").removeAttr("disabled")
|
||||
$("#public_key").val("")
|
||||
}
|
||||
})
|
||||
$('#add_modal').on('show.bs.modal', function (event) {
|
||||
generate_key()
|
||||
})
|
||||
$("#re_generate_key").click(function (){
|
||||
$("#public_key").attr("disabled","disabled")
|
||||
$("#re_generate_key i").addClass("rotating")
|
||||
generate_key()
|
||||
})
|
||||
|
||||
$("body").on("click", ".switch", function (){
|
||||
$(this).siblings($(".spinner-border")).css("display", "inline-block");
|
||||
$(this).remove()
|
||||
location.replace("/switch/"+$(this).attr('id'));
|
||||
})
|
||||
|
||||
|
||||
|
||||
$("#save_peer").click(function(){
|
||||
if ($("#allowed_ips") !== "" && $("#public_key") !== ""){
|
||||
var conf = $(this).attr('conf_id')
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/add_peer/"+conf,
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({
|
||||
"private_key":$("#private_key").val(),
|
||||
"public_key":$("#public_key").val(),
|
||||
"allowed_ips": $("#allowed_ips").val(),
|
||||
"name":$("#new_add_name").val()
|
||||
}),
|
||||
success: function (response){
|
||||
if(response != "true"){
|
||||
$("#add_peer_alert").html(response+$("#add_peer_alert").html());
|
||||
$("#add_peer_alert").removeClass("d-none");
|
||||
}
|
||||
else{
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
var qrcodeModal = new bootstrap.Modal(document.getElementById('qrcode_modal'), {
|
||||
keyboard: false
|
||||
})
|
||||
|
||||
$("body").on("click", ".btn-qrcode-peer", function (){
|
||||
qrcodeModal.toggle();
|
||||
$("#qrcode_img").attr('src', $(this).attr('img_src'))
|
||||
})
|
||||
|
||||
var deleteModal = new bootstrap.Modal(document.getElementById('delete_modal'), {
|
||||
keyboard: false
|
||||
});
|
||||
|
||||
$("body").on("click", ".btn-delete-peer", function(){
|
||||
var peer_id = $(this).attr("id");
|
||||
$("#delete_peer").attr("peer_id", peer_id);
|
||||
deleteModal.toggle();
|
||||
})
|
||||
|
||||
$("#delete_peer").click(function(){
|
||||
var peer_id = $(this).attr("peer_id");
|
||||
var config = $(this).attr("conf_id");
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/remove_peer/"+config,
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({"action": "delete", "peer_id": peer_id}),
|
||||
success: function (response){
|
||||
if(response !== "true"){
|
||||
$("#remove_peer_alert").html(response+$("#add_peer_alert").html());
|
||||
$("#remove_peer_alert").removeClass("d-none");
|
||||
}
|
||||
else{
|
||||
deleteModal.toggle();
|
||||
load_data();
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html("Peer deleted!");
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var settingModal = new bootstrap.Modal(document.getElementById('setting_modal'), {
|
||||
keyboard: false
|
||||
})
|
||||
|
||||
$("body").on("click", ".btn-setting-peer", function(){
|
||||
settingModal.toggle();
|
||||
var peer_id = $(this).attr("id");
|
||||
$("#save_peer_name").attr("peer_id", peer_id);
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/get_peer_name/"+$("#setting_modal").attr("conf_id"),
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({"id": peer_id}),
|
||||
success: function(response){
|
||||
if (response == ""){
|
||||
$("#setting_modal .peer_name").html("Untitled Peer");
|
||||
$("#peer_name_textbox").val("")
|
||||
}else{
|
||||
$("#setting_modal .peer_name").html(response);
|
||||
$("#peer_name_textbox").val(response)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
$("#save_peer_name").click(function (){
|
||||
var peer_id = $(this).attr("peer_id");
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/save_peer_name/"+"{{conf_data['name']}}",
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: JSON.stringify({id: peer_id, name: $("#peer_name_textbox").val()}),
|
||||
success: function (response){
|
||||
settingModal.toggle();
|
||||
load_data();
|
||||
$('#alertToast').toast('show');
|
||||
$('#alertToast .toast-body').html("Name Saved!");
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
<script src="{{ url_for('static',filename='configuration.js') }}"></script>
|
||||
</html>
|
@@ -6,4 +6,4 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="{{ url_for('static',filename='tools.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='tools.js') }}"></script>
|
||||
|
@@ -107,14 +107,21 @@
|
||||
</div>
|
||||
<div class="w-100"></div>
|
||||
<div class="col-sm">
|
||||
<div class="button-group">
|
||||
<hr>
|
||||
<hr>
|
||||
<div class="button-group" style="display:flex">
|
||||
|
||||
<button type="button" class="btn btn-outline-primary btn-setting-peer btn-control" id="{{i['id']}}" data-toggle="modal"><i class="bi bi-gear-fill"></i></button>
|
||||
<button type="button" class="btn btn-outline-danger btn-delete-peer btn-control" id="{{i['id']}}" data-toggle="modal"><i class="bi bi-x-circle-fill"></i></button>
|
||||
{% if i['private_key'] %}
|
||||
<button type="button" class="btn btn-outline-success btn-qrcode-peer btn-control" img_src="{{ qrcode("[Interface]\nPrivateKey = "+i['private_key']+"\nAddress = "+i['allowed_ip']+"\nDNS = 1.1.1.1\n\n[Peer]\nPublicKey = "+conf_data['public_key']+"\nAllowedIPs = 0.0.0.0/0\nEndpoint = "+wg_ip+":"+conf_data['listen_port']) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 19px;" fill="#28a745"><path d="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zM13 3v8h8V3h-8zm6 6h-4V5h4v4zM13 13h2v2h-2zM15 15h2v2h-2zM13 17h2v2h-2zM17 17h2v2h-2zM19 19h2v2h-2zM15 19h2v2h-2zM17 13h2v2h-2zM19 15h2v2h-2z"/></svg>
|
||||
</button>
|
||||
<div class="share_peer_btn_group" style="margin-left: auto !important; display: inline">
|
||||
<button type="button" class="btn btn-outline-success btn-qrcode-peer btn-control" img_src="{{ qrcode("[Interface]\nPrivateKey = "+i['private_key']+"\nAddress = "+i['allowed_ip']+"\nDNS = 1.1.1.1\n\n[Peer]\nPublicKey = "+conf_data['public_key']+"\nAllowedIPs = 0.0.0.0/0\nEndpoint = "+wg_ip+":"+conf_data['listen_port']) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 19px;" fill="#28a745"><path d="M3 11h8V3H3v8zm2-6h4v4H5V5zM3 21h8v-8H3v8zm2-6h4v4H5v-4zM13 3v8h8V3h-8zm6 6h-4V5h4v4zM13 13h2v2h-2zM15 15h2v2h-2zM13 17h2v2h-2zM17 17h2v2h-2zM19 19h2v2h-2zM15 19h2v2h-2zM17 13h2v2h-2zM19 15h2v2h-2z"/></svg>
|
||||
</button>
|
||||
<a href="/download/{{ conf_data['name'] }}?id={{ i['id']|urlencode }}" type="button" class="btn btn-outline-info btn-download-peer btn-control">
|
||||
<i class="bi bi-download"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -93,9 +93,9 @@ if [ "$#" != 1 ];
|
||||
stop_wgd
|
||||
sleep 2
|
||||
printf "Wireguard Dashboard is stopped. \n"
|
||||
start_wgd_debug
|
||||
start_wgd
|
||||
else
|
||||
start_wgd_debug
|
||||
start_wgd
|
||||
fi
|
||||
elif [ "$1" = "debug" ]; then
|
||||
if check_wgd_status; then
|
||||
|
Reference in New Issue
Block a user