mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-06 16:00:28 +01:00
Finished developing add config
This commit is contained in:
parent
cc1dd682e8
commit
46efe2b8dd
95
src/api.py
95
src/api.py
@ -1,2 +1,95 @@
|
|||||||
from dashboard import request, jsonify, app
|
import ipaddress, subprocess, datetime, os, util
|
||||||
|
from util import *
|
||||||
|
notEnoughParameter = {"status": False, "reason": "Please provide all required parameters."}
|
||||||
|
good = {"status": True, "reason": ""}
|
||||||
|
|
||||||
|
def togglePeerAccess(data, g):
|
||||||
|
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
||||||
|
if checkUnlock:
|
||||||
|
moveUnlockToLock = g.cur.execute(f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
||||||
|
if g.cur.rowcount == 1:
|
||||||
|
print(g.cur.rowcount)
|
||||||
|
print(util.deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
||||||
|
else:
|
||||||
|
moveLockToUnlock = g.cur.execute(f"SELECT * FROM {data['config']}_restrict_access WHERE id='{data['peerID']}'").fetchone()
|
||||||
|
try:
|
||||||
|
if len(moveLockToUnlock[-1]) == 0:
|
||||||
|
status = subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
else:
|
||||||
|
now = str(datetime.datetime.now().strftime("%m%d%Y%H%M%S"))
|
||||||
|
f_name = now + "_tmp_psk.txt"
|
||||||
|
f = open(f_name, "w+")
|
||||||
|
f.write(moveLockToUnlock[-1])
|
||||||
|
f.close()
|
||||||
|
subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]} preshared-key {f_name}",
|
||||||
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
|
os.remove(f_name)
|
||||||
|
status = subprocess.check_output(f"wg-quick save {data['config']}", shell=True, stderr=subprocess.STDOUT)
|
||||||
|
g.cur.execute(f"INSERT INTO {data['config']} SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||||
|
if g.cur.rowcount == 1:
|
||||||
|
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
return {"status": False, "reason": str(exc.output.strip())}
|
||||||
|
return good
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class addConfiguration:
|
||||||
|
def AddressCheck(data):
|
||||||
|
address = data['address']
|
||||||
|
address = address.replace(" ", "")
|
||||||
|
address = address.split(',')
|
||||||
|
amount = 0
|
||||||
|
for i in address:
|
||||||
|
try:
|
||||||
|
ips = ipaddress.ip_network(i, False)
|
||||||
|
amount += ips.num_addresses
|
||||||
|
except ValueError as e:
|
||||||
|
return {"status": False, "reason": str(e)}
|
||||||
|
if amount >= 1:
|
||||||
|
return {"status": True, "reason":"", "data":f"Total of {amount} IPs"}
|
||||||
|
else:
|
||||||
|
return {"status": True, "reason":"", "data":f"0 available IPs"}
|
||||||
|
|
||||||
|
def PortCheck(data, configs):
|
||||||
|
port = data['port']
|
||||||
|
if (not port.isdigit()) or int(port) < 1 or int(port) > 65535:
|
||||||
|
return {"status": False, "reason": f"Invalid port."}
|
||||||
|
for i in configs:
|
||||||
|
if i['port'] == port:
|
||||||
|
return {"status": False, "reason": f"{port} used by {i['conf']}."}
|
||||||
|
return good
|
||||||
|
|
||||||
|
def NameCheck(data, configs):
|
||||||
|
name = data['name']
|
||||||
|
name = name.replace(" ", "")
|
||||||
|
for i in configs:
|
||||||
|
if name == i['conf']:
|
||||||
|
return {"status": False, "reason":f"{name} already existed."}
|
||||||
|
return good
|
||||||
|
|
||||||
|
def addConfiguration(data, configs, WG_CONF_PATH):
|
||||||
|
output = ["[Interface]", "SaveConfig = true"]
|
||||||
|
required = ['addConfigurationPrivateKey', 'addConfigurationListenPort',
|
||||||
|
'addConfigurationAddress', 'addConfigurationPreUp', 'addConfigurationPreDown',
|
||||||
|
'addConfigurationPostUp', 'addConfigurationPostDown']
|
||||||
|
for i in required:
|
||||||
|
e = data[i]
|
||||||
|
if len(e) != 0:
|
||||||
|
key = i.replace("addConfiguration", "")
|
||||||
|
o = f"{key} = {e}"
|
||||||
|
output.append(o)
|
||||||
|
name = data['addConfigurationName']
|
||||||
|
illegal_filename = [" ",".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3",
|
||||||
|
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
|
||||||
|
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
|
||||||
|
for i in illegal_filename:
|
||||||
|
name = name.replace(i, "")
|
||||||
|
try:
|
||||||
|
newFile = open(f"{WG_CONF_PATH}/{name}.conf", "w+")
|
||||||
|
newFile.write("\n".join(output))
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": False, "reason":str(e)}
|
||||||
|
return {"status": True, "reason":"", "data": name}
|
105
src/dashboard.py
105
src/dashboard.py
@ -31,7 +31,7 @@ from flask_socketio import SocketIO
|
|||||||
from util import *
|
from util import *
|
||||||
|
|
||||||
# Dashboard Version
|
# Dashboard Version
|
||||||
DASHBOARD_VERSION = 'v3.0.5'
|
DASHBOARD_VERSION = 'v3.1'
|
||||||
|
|
||||||
# WireGuard's configuration path
|
# WireGuard's configuration path
|
||||||
WG_CONF_PATH = None
|
WG_CONF_PATH = None
|
||||||
@ -58,6 +58,7 @@ socketio = SocketIO(app)
|
|||||||
|
|
||||||
# TODO: use class and object oriented programming
|
# TODO: use class and object oriented programming
|
||||||
|
|
||||||
|
|
||||||
def connect_db():
|
def connect_db():
|
||||||
"""
|
"""
|
||||||
Connect to the database
|
Connect to the database
|
||||||
@ -521,7 +522,7 @@ def get_conf_list():
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
g.cur.execute(create_table)
|
g.cur.execute(create_table)
|
||||||
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), "port": get_conf_listen_port(i)}
|
||||||
if temp['status'] == "running":
|
if temp['status'] == "running":
|
||||||
temp['checked'] = 'checked'
|
temp['checked'] = 'checked'
|
||||||
else:
|
else:
|
||||||
@ -731,6 +732,7 @@ def auth():
|
|||||||
if password.hexdigest() == config["Account"]["password"] \
|
if password.hexdigest() == config["Account"]["password"] \
|
||||||
and data['username'] == config["Account"]["username"]:
|
and data['username'] == config["Account"]["username"]:
|
||||||
session['username'] = data['username']
|
session['username'] = data['username']
|
||||||
|
session.permanent = True
|
||||||
config.clear()
|
config.clear()
|
||||||
return jsonify({"status": True, "msg": ""})
|
return jsonify({"status": True, "msg": ""})
|
||||||
config.clear()
|
config.clear()
|
||||||
@ -1107,15 +1109,15 @@ def switch(config_name):
|
|||||||
check = subprocess.check_output("wg-quick down " + config_name,
|
check = subprocess.check_output("wg-quick down " + config_name,
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
session["switch_msg"] = exc.output.strip().decode("utf-8")
|
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||||
return jsonify({"status": False, "reason":"Can't stop peer"})
|
return jsonify({"status": False, "reason":"Can't stop peer", "message": str(exc.output.strip().decode("utf-8"))})
|
||||||
elif status == "stopped":
|
elif status == "stopped":
|
||||||
try:
|
try:
|
||||||
subprocess.check_output("wg-quick up " + config_name,
|
subprocess.check_output("wg-quick up " + config_name,
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
shell=True, stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
session["switch_msg"] = exc.output.strip().decode("utf-8")
|
# session["switch_msg"] = exc.output.strip().decode("utf-8")
|
||||||
return jsonify({"status": False, "reason":"Can't turn on peer"})
|
return jsonify({"status": False, "reason":"Can't turn on peer", "message": str(exc.output.strip().decode("utf-8"))})
|
||||||
return jsonify({"status": True, "reason":""})
|
return jsonify({"status": True, "reason":""})
|
||||||
|
|
||||||
@app.route('/add_peer_bulk/<config_name>', methods=['POST'])
|
@app.route('/add_peer_bulk/<config_name>', methods=['POST'])
|
||||||
@ -1534,45 +1536,18 @@ def switch_display_mode(mode):
|
|||||||
|
|
||||||
|
|
||||||
# APIs
|
# APIs
|
||||||
|
import api
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/togglePeerAccess', methods=['POST'])
|
@app.route('/api/togglePeerAccess', methods=['POST'])
|
||||||
def togglePeerAccess():
|
def togglePeerAccess():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
returnData = {"status": True, "reason": ""}
|
returnData = {"status": True, "reason": ""}
|
||||||
required = ['peerID', 'config']
|
required = ['peerID', 'config']
|
||||||
if checkJSONAllParameter(required, data):
|
if checkJSONAllParameter(required, data):
|
||||||
checkUnlock = g.cur.execute(f"SELECT * FROM {data['config']} WHERE id='{data['peerID']}'").fetchone()
|
returnData = api.togglePeerAccess(data, g)
|
||||||
if checkUnlock:
|
|
||||||
moveUnlockToLock = g.cur.execute(f"INSERT INTO {data['config']}_restrict_access SELECT * FROM {data['config']} WHERE id = '{data['peerID']}'")
|
|
||||||
if g.cur.rowcount == 1:
|
|
||||||
print(g.cur.rowcount)
|
|
||||||
print(deletePeers(data['config'], [data['peerID']], g.cur, g.db))
|
|
||||||
else:
|
|
||||||
moveLockToUnlock = g.cur.execute(f"SELECT * FROM {data['config']}_restrict_access WHERE id='{data['peerID']}'").fetchone()
|
|
||||||
try:
|
|
||||||
if len(moveLockToUnlock[-1]) == 0:
|
|
||||||
status = subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]}",
|
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
|
||||||
else:
|
|
||||||
now = str(datetime.now().strftime("%m%d%Y%H%M%S"))
|
|
||||||
f_name = now + "_tmp_psk.txt"
|
|
||||||
f = open(f_name, "w+")
|
|
||||||
f.write(moveLockToUnlock[-1])
|
|
||||||
f.close()
|
|
||||||
subprocess.check_output(f"wg set {data['config']} peer {moveLockToUnlock[0]} allowed-ips {moveLockToUnlock[11]} preshared-key {f_name}",
|
|
||||||
shell=True, stderr=subprocess.STDOUT)
|
|
||||||
os.remove(f_name)
|
|
||||||
status = subprocess.check_output(f"wg-quick save {data['config']}", shell=True, stderr=subprocess.STDOUT)
|
|
||||||
g.cur.execute(f"INSERT INTO {data['config']} SELECT * FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
|
||||||
if g.cur.rowcount == 1:
|
|
||||||
g.cur.execute(f"DELETE FROM {data['config']}_restrict_access WHERE id = '{data['peerID']}'")
|
|
||||||
|
|
||||||
except subprocess.CalledProcessError as exc:
|
|
||||||
returnData["status"] = False
|
|
||||||
returnData["reason"] = exc.output.strip()
|
|
||||||
else:
|
else:
|
||||||
returnData["status"] = False
|
return jsonify(api.notEnoughParameter)
|
||||||
returnData["reason"] = "Please provide all required parameters."
|
|
||||||
|
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
|
|
||||||
@app.route('/api/addConfigurationAddressCheck', methods=['POST'])
|
@app.route('/api/addConfigurationAddressCheck', methods=['POST'])
|
||||||
@ -1581,20 +1556,52 @@ def addConfigurationAddressCheck():
|
|||||||
returnData = {"status": True, "reason": ""}
|
returnData = {"status": True, "reason": ""}
|
||||||
required = ['address']
|
required = ['address']
|
||||||
if checkJSONAllParameter(required, data):
|
if checkJSONAllParameter(required, data):
|
||||||
try:
|
returnData = api.addConfiguration.AddressCheck(data)
|
||||||
ips = list(ipaddress.ip_network(data['address'], False).hosts())
|
|
||||||
amount = len(ips) - 1
|
|
||||||
if amount >= 1:
|
|
||||||
returnData = {"status": True, "reason":"", "data":f"Total of {amount} IPs"}
|
|
||||||
else:
|
|
||||||
returnData = {"status": True, "reason":"", "data":f"0 IP available for peers"}
|
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
returnData = {"status": False, "reason": str(e)}
|
|
||||||
else:
|
else:
|
||||||
returnData = {"status": False, "reason": "Please provide all required parameters."}
|
return jsonify(api.notEnoughParameter)
|
||||||
return jsonify(returnData)
|
return jsonify(returnData)
|
||||||
|
|
||||||
|
@app.route('/api/addConfigurationPortCheck', methods=['POST'])
|
||||||
|
def addConfigurationPortCheck():
|
||||||
|
data = request.get_json()
|
||||||
|
returnData = {"status": True, "reason": ""}
|
||||||
|
required = ['port']
|
||||||
|
if checkJSONAllParameter(required, data):
|
||||||
|
returnData = api.addConfiguration.PortCheck(data, get_conf_list())
|
||||||
|
else:
|
||||||
|
return jsonify(api.notEnoughParameter)
|
||||||
|
return jsonify(returnData)
|
||||||
|
|
||||||
|
@app.route('/api/addConfigurationNameCheck', methods=['POST'])
|
||||||
|
def addConfigurationNameCheck():
|
||||||
|
data = request.get_json()
|
||||||
|
returnData = {"status": True, "reason": ""}
|
||||||
|
required = ['name']
|
||||||
|
if checkJSONAllParameter(required, data):
|
||||||
|
returnData = api.addConfiguration.NameCheck(data, get_conf_list())
|
||||||
|
else:
|
||||||
|
return jsonify(api.notEnoughParameter)
|
||||||
|
return jsonify(returnData)
|
||||||
|
|
||||||
|
@app.route('/api/addConfiguration', methods=["POST"])
|
||||||
|
def addConfiguration():
|
||||||
|
data = request.get_json()
|
||||||
|
returnData = {"status": True, "reason": ""}
|
||||||
|
required = ['addConfigurationPrivateKey', 'addConfigurationName', 'addConfigurationListenPort',
|
||||||
|
'addConfigurationAddress', 'addConfigurationPreUp', 'addConfigurationPreDown',
|
||||||
|
'addConfigurationPostUp', 'addConfigurationPostDown']
|
||||||
|
needFilled = ['addConfigurationPrivateKey', 'addConfigurationName', 'addConfigurationListenPort',
|
||||||
|
'addConfigurationAddress']
|
||||||
|
if not checkJSONAllParameter(needFilled, data):
|
||||||
|
return jsonify(api.notEnoughParameter)
|
||||||
|
for i in required:
|
||||||
|
if i not in data.keys():
|
||||||
|
return jsonify(api.notEnoughParameter)
|
||||||
|
|
||||||
|
returnData = api.addConfiguration.addConfiguration(data, get_conf_list(), WG_CONF_PATH)
|
||||||
|
return jsonify(returnData)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Dashboard Tools Related
|
Dashboard Tools Related
|
||||||
|
@ -773,3 +773,18 @@ pre.index-alert {
|
|||||||
.input-feedback{
|
.input-feedback{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#addConfigurationModal label{
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#addConfigurationModal label a{
|
||||||
|
margin-left: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reGeneratePrivateKey{
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
@ -1,9 +1,22 @@
|
|||||||
let numberToast = 0;
|
let numberToast = 0;
|
||||||
let addConfigurationModal = new bootstrap.Modal(document.getElementById('addConfigurationModal'), {
|
let emptyInputFeedback = "Can't leave empty";
|
||||||
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
let $add_configuration = $("#add_configuration");
|
||||||
|
|
||||||
|
let addConfigurationModal = $("#addConfigurationModal");
|
||||||
|
|
||||||
|
addConfigurationModal.modal({
|
||||||
keyboard: false,
|
keyboard: false,
|
||||||
backdrop: 'static'
|
backdrop: 'static',
|
||||||
|
show: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addConfigurationModal.on("hidden.bs.modal", function(){
|
||||||
|
$("#add_configuration_form").trigger("reset");
|
||||||
|
$("#add_configuration_form input").removeClass("is-valid").removeClass("is-invalid");
|
||||||
|
$(".addConfigurationAvailableIPs").text("N/A");
|
||||||
|
})
|
||||||
|
|
||||||
function showToast(msg){
|
function showToast(msg){
|
||||||
$(".toastContainer").append(
|
$(".toastContainer").append(
|
||||||
`<div id="${numberToast}-toast" class="toast hide" role="alert" data-delay="5000">
|
`<div id="${numberToast}-toast" class="toast hide" role="alert" data-delay="5000">
|
||||||
@ -34,35 +47,32 @@ $(".toggle--switch").on("change", function(){
|
|||||||
}).done(function(res){
|
}).done(function(res){
|
||||||
let dot = $(`div[data-conf-id="${id}"] .dot`);
|
let dot = $(`div[data-conf-id="${id}"] .dot`);
|
||||||
console.log();
|
console.log();
|
||||||
if (res){
|
if (res.status){
|
||||||
if (status){
|
if (status){
|
||||||
dot.removeClass("dot-stopped").addClass("dot-running");
|
dot.removeClass("dot-stopped").addClass("dot-running");
|
||||||
dot.siblings().text("Running");
|
dot.siblings().text("Running");
|
||||||
showToast(`${id} is running.`)
|
showToast(`${id} is running.`);
|
||||||
}else{
|
}else{
|
||||||
dot.removeClass("dot-running").addClass("dot-stopped");
|
dot.removeClass("dot-running").addClass("dot-stopped");
|
||||||
showToast(`${id} is stopped.`)
|
showToast(`${id} is stopped.`);
|
||||||
}
|
}
|
||||||
ele.removeClass("waiting");
|
|
||||||
ele.removeAttr("disabled");
|
|
||||||
}else{
|
}else{
|
||||||
|
// $(".index-alert").removeClass("d-none");
|
||||||
|
// $(".index-alert-full code").text(res.message);
|
||||||
|
ele.parents().children(".card-message").html(`<pre class="index-alert">Configuration toggle failed. Please check the following error message:<br><code>${res.message}</code></pre>`)
|
||||||
|
|
||||||
|
|
||||||
if (status){
|
if (status){
|
||||||
$(this).prop("checked", false)
|
ele.prop("checked", false)
|
||||||
}else{
|
}else{
|
||||||
$(this).prop("checked", true)
|
ele.prop("checked", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ele.removeClass("waiting").removeAttr("disabled");
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.switch').on("click", function() {
|
|
||||||
$(this).siblings($(".spinner-border")).css("display", "inline-block")
|
|
||||||
$(this).remove()
|
|
||||||
location.replace("/switch/"+$(this).attr('id'))
|
|
||||||
});
|
|
||||||
$(".sb-home-url").addClass("active");
|
$(".sb-home-url").addClass("active");
|
||||||
|
|
||||||
$(".card-body").on("click", function(handle){
|
$(".card-body").on("click", function(handle){
|
||||||
if ($(handle.target).attr("class") !== "toggleLabel" && $(handle.target).attr("class") !== "toggle--switch") {
|
if ($(handle.target).attr("class") !== "toggleLabel" && $(handle.target).attr("class") !== "toggle--switch") {
|
||||||
window.open($(this).find("a").attr("href"), "_self");
|
window.open($(this).find("a").attr("href"), "_self");
|
||||||
@ -71,8 +81,7 @@ $(".card-body").on("click", function(handle){
|
|||||||
|
|
||||||
function genKeyPair(){
|
function genKeyPair(){
|
||||||
let keyPair = window.wireguard.generateKeypair();
|
let keyPair = window.wireguard.generateKeypair();
|
||||||
$("#addConfigurationPrivateKey").val(keyPair.privateKey);
|
$("#addConfigurationPrivateKey").val(keyPair.privateKey).data("checked", true);
|
||||||
$("#addConfigurationPublicKey").attr("disabled", "disabled").val(keyPair.publicKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#reGeneratePrivateKey").on("click", function() {
|
$("#reGeneratePrivateKey").on("click", function() {
|
||||||
@ -80,39 +89,168 @@ $("#reGeneratePrivateKey").on("click", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#toggleAddConfiguration").on("click", function(){
|
$("#toggleAddConfiguration").on("click", function(){
|
||||||
addConfigurationModal.toggle();
|
addConfigurationModal.modal('toggle');
|
||||||
genKeyPair()
|
genKeyPair()
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#addConfigurationPrivateKey").on("change", function() {
|
$("#addConfigurationPrivateKey").on("change", function() {
|
||||||
let $publicKey = $("#addConfigurationPublicKey");
|
$privateKey = $(this);
|
||||||
if ($(this).val().length === 44) {
|
$privateKeyFeedback = $("#addConfigurationPrivateKeyFeedback");
|
||||||
$publicKey.attr("disabled", "disabled").val(window.wireguard.generatePublicKey($(this).val()));
|
if ($privateKey.val().length != 44){
|
||||||
} else {
|
invalidInput($privateKey, $privateKeyFeedback, "Invalid length");
|
||||||
$publicKey.removeAttr("disabled").val("");
|
}else{
|
||||||
|
validInput($privateKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#addConfigurationAddress").on("change", function(){
|
function ajaxPostJSON(url, data, doneFunc){
|
||||||
let address = $("#addConfigurationAddress");
|
|
||||||
let addressFeedback = $("#addConfigurationAddressFeedback");
|
|
||||||
let availableIPs = $(".addConfigurationAvailableIPs");
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/addConfigurationAddressCheck",
|
url: url,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json"},
|
data: JSON.stringify(data),
|
||||||
data: JSON.stringify({
|
headers: {"Content-Type": "application/json"}
|
||||||
"address": $(this).val()
|
}).done(function (res) {
|
||||||
})
|
doneFunc(res);
|
||||||
}).done(function(res){
|
});
|
||||||
console.log(res)
|
}
|
||||||
if (res.status){
|
function validInput(input){
|
||||||
availableIPs.html(`<strong>${res.data}</strong>`);
|
input.removeClass("is-invalid").addClass("is-valid").removeAttr("disabled").data("checked", true);
|
||||||
address.removeClass("is-invalid").addClass("is-valid");
|
}
|
||||||
}else{
|
function invalidInput(input, feedback, text){
|
||||||
address.addClass("is-invalid");
|
input.removeClass("is-valid").addClass("is-invalid").removeAttr("disabled").data("checked", false);
|
||||||
addressFeedback.addClass("invalid-feedback").text(res.reason);
|
feedback.addClass("invalid-feedback").text(text);
|
||||||
availableIPs.html(`N/A`);
|
}
|
||||||
|
|
||||||
|
function checkPort($this){
|
||||||
|
let port = $this;
|
||||||
|
port.attr("disabled", "disabled");
|
||||||
|
let portFeedback = $("#addConfigurationListenPortFeedback");
|
||||||
|
if (port.val().length == 0){
|
||||||
|
invalidInput(port, portFeedback, emptyInputFeedback)
|
||||||
|
}else{
|
||||||
|
function done(res){
|
||||||
|
if(res.status){
|
||||||
|
validInput(port);
|
||||||
|
}else{
|
||||||
|
invalidInput(port, portFeedback, res.reason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
ajaxPostJSON('/api/addConfigurationPortCheck', {"port": port.val()}, done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#addConfigurationListenPort").on("change", function(){
|
||||||
|
checkPort($(this));
|
||||||
|
})
|
||||||
|
|
||||||
|
function checkAddress($this){
|
||||||
|
let address = $this;
|
||||||
|
address.attr("disabled", "disabled");
|
||||||
|
let availableIPs = $(".addConfigurationAvailableIPs");
|
||||||
|
let addressFeedback = $("#addConfigurationAddressFeedback");
|
||||||
|
if (address.val().length == 0){
|
||||||
|
invalidInput(address, addressFeedback, emptyInputFeedback);
|
||||||
|
availableIPs.html(`N/A`);
|
||||||
|
}else{
|
||||||
|
function done(res){
|
||||||
|
if (res.status){
|
||||||
|
availableIPs.html(`<strong>${res.data}</strong>`);
|
||||||
|
validInput(address);
|
||||||
|
}else{
|
||||||
|
invalidInput(address, addressFeedback, res.reason);
|
||||||
|
availableIPs.html(`N/A`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxPostJSON("/api/addConfigurationAddressCheck", {"address": address.val()}, done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#addConfigurationAddress").on("change", function(){
|
||||||
|
checkAddress($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function checkName($this){
|
||||||
|
let name = $this;
|
||||||
|
let nameFeedback = $("#addConfigurationNameFeedback");
|
||||||
|
name.val(name.val().replace(/\s/g,'')).attr("disabled", "disabled");
|
||||||
|
if (name.val().length === 0){
|
||||||
|
invalidInput(name, nameFeedback, emptyInputFeedback)
|
||||||
|
}else{
|
||||||
|
function done(res){
|
||||||
|
if (res.status){
|
||||||
|
validInput(name);
|
||||||
|
}else{
|
||||||
|
invalidInput(name, nameFeedback, res.reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxPostJSON("/api/addConfigurationNameCheck", {"name": name.val()}, done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#addConfigurationName").on("change", function(){
|
||||||
|
checkName($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$("#addConfigurationBtn").on("click", function(){
|
||||||
|
let btn = $(this);
|
||||||
|
let input = $("#add_configuration_form input");
|
||||||
|
let filled = true;
|
||||||
|
for (let i = 0; i < input.length; i++){
|
||||||
|
let $i = $(input[i]);
|
||||||
|
if ($i.attr("required") != undefined){
|
||||||
|
if ($i.val().length == 0 && $i.attr("name") !== "addConfigurationPrivateKey"){
|
||||||
|
invalidInput($i, $i.siblings(".input-feedback"), emptyInputFeedback);
|
||||||
|
filled = false;
|
||||||
|
}
|
||||||
|
if ($i.val().length != 44 && $i.attr("name") == "addConfigurationPrivateKey"){
|
||||||
|
invalidInput($i, $i.siblings(".input-feedback"), "Invalid length");
|
||||||
|
filled = false;
|
||||||
|
}
|
||||||
|
if (!$i.data("checked")){
|
||||||
|
filled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filled){
|
||||||
|
$("#addConfigurationModal .modal-footer .btn").hide();
|
||||||
|
$(".addConfigurationStatus").removeClass("d-none").html(`<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div> Adding peers`)
|
||||||
|
let data = {};
|
||||||
|
let q = [];
|
||||||
|
for (let i = 0; i < input.length; i++){
|
||||||
|
let $i = $(input[i]);
|
||||||
|
data[$i.attr("name")] = $i.val();
|
||||||
|
q.push($i.attr("name"))
|
||||||
|
}
|
||||||
|
function done(res){
|
||||||
|
let name = res.data;
|
||||||
|
if (res.status){
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
$(".addConfigurationStatus").html(`<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div> Toggling ${res.data}`)
|
||||||
|
$.ajax({
|
||||||
|
url: `/switch/${name}`
|
||||||
|
}).done(function(res){
|
||||||
|
if (res.status){
|
||||||
|
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-success").html(`<i class="bi bi-check-circle-fill"></i> ${name} toggled! Refresh in 5 seconds.`);
|
||||||
|
setTimeout(() => {
|
||||||
|
$(".addConfigurationStatus").text("Refeshing...")
|
||||||
|
location.reload();
|
||||||
|
}, 5000);
|
||||||
|
}else{
|
||||||
|
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} toggle failed.`)
|
||||||
|
$("#addCconfigurationAlert").removeClass("d-none").children(".alert-body").text(res.reason);
|
||||||
|
$("#addCconfigurationAlertMessage").removeClass("d-none").text(res.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$(".addConfigurationStatus").removeClass("text-primary").addClass("text-danger").html(`<i class="bi bi-x-circle-fill"></i> ${name} adding failed.`)
|
||||||
|
$("#addCconfigurationAlert").removeClass("d-none").children(".alert-body").text(res.reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxPostJSON("/api/addConfiguration", data, done);
|
||||||
|
}
|
||||||
});
|
});
|
@ -13,12 +13,16 @@
|
|||||||
<div style="display: flex; flex-direction: row; align-items: center;">
|
<div style="display: flex; flex-direction: row; align-items: center;">
|
||||||
<h1 class="pb-4 mt-4">Home</h1>
|
<h1 class="pb-4 mt-4">Home</h1>
|
||||||
</div>
|
</div>
|
||||||
{% if msg != "" %}
|
<!-- {% if msg != "" %}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
Configuration toggle failed. Please check the following error message:
|
Configuration toggle failed. Please check the following error message:
|
||||||
</div>
|
</div>
|
||||||
<pre class="index-alert"><code>{{ msg }}</code></pre>
|
<pre class="index-alert"><code>{{ msg }}</code></pre>
|
||||||
{% endif %}
|
{% endif %} -->
|
||||||
|
<div class="index-alert alert alert-danger d-none" role="alert">
|
||||||
|
Configuration toggle failed. Please check the following error message:
|
||||||
|
</div>
|
||||||
|
<pre class="index-alert index-alert-full d-none"><code></code></pre>
|
||||||
|
|
||||||
{% if conf == [] %}
|
{% if conf == [] %}
|
||||||
<p class="text-muted">You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".</p>
|
<p class="text-muted">You don't have any WireGuard configurations yet. Please check the configuration folder or change it in "Settings". By default the folder is "/etc/wireguard".</p>
|
||||||
@ -48,17 +52,11 @@
|
|||||||
<input type="checkbox" class="toggle--switch" id="{{i['conf']}}-switch" {{i['checked']}} data-conf-id="{{i['conf']}}">
|
<input type="checkbox" class="toggle--switch" id="{{i['conf']}}-switch" {{i['checked']}} data-conf-id="{{i['conf']}}">
|
||||||
<label for="{{i['conf']}}-switch" class="toggleLabel"></label>
|
<label for="{{i['conf']}}-switch" class="toggleLabel"></label>
|
||||||
</div>
|
</div>
|
||||||
<!-- {% if i['checked'] == "checked" %}
|
|
||||||
<a href="#" id="{{i['conf']}}" class="switch text-primary tt"><i class="bi bi-toggle2-on"></i></a>
|
|
||||||
{% else %}
|
|
||||||
<a href="#" id="{{i['conf']}}" {{i['checked']}} class="switch text-secondary"><i class="bi bi-toggle2-off"></i></a>
|
|
||||||
{% endif %} -->
|
|
||||||
<!-- <div class="spinner-border text-primary" role="status" style="display: none">
|
|
||||||
<span class="sr-only">Loading...</span>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-message"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</main>
|
</main>
|
||||||
@ -84,53 +82,49 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="alert-body"></div>
|
<div class="alert-body"></div>
|
||||||
</div>
|
</div>
|
||||||
<form id="add_peer_form">
|
<pre id="addCconfigurationAlertMessage" class="index-alert d-none"></pre>
|
||||||
|
<form id="add_configuration_form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
<label for="addConfigurationPrivateKey">Private Key</label>
|
<label for="addConfigurationPrivateKey">Private Key <code>*</code></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPrivateKey" aria-describedby="addConfigurationPrivateKey">
|
<input type="text" class="form-control codeFont" id="addConfigurationPrivateKey" name="addConfigurationPrivateKey" required>
|
||||||
<div class="input-group-append">
|
<div class="input-group-append">
|
||||||
<button type="button" class="btn btn-danger" id="reGeneratePrivateKey" data-toggle="tooltip" data-placement="top" title="Regenerate Key"><i class="bi bi-arrow-repeat"></i></button>
|
<button type="button" class="btn btn-danger" id="reGeneratePrivateKey" data-toggle="tooltip" data-placement="top" title="Regenerate Key"><i class="bi bi-arrow-repeat"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div id="addConfigurationPrivateKeyFeedback" class="input-feedback"></div>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div>
|
|
||||||
<label for="addConfigurationPublicKey">Public Key</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPublicKey" aria-describedby="addConfigurationPublicKey" disabled>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationName">Configuration Name <code>(Required)</code></label>
|
<label for="addConfigurationName">Configuration Name <code>*</code></label>
|
||||||
<input type="text" class="form-control" id="addConfigurationName">
|
<input type="text" class="form-control" id="addConfigurationName" name="addConfigurationName" required>
|
||||||
|
<div id="addConfigurationNameFeedback" class="input-feedback"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationListenPort">Listen Port <code>(Required)</code></label>
|
<label for="addConfigurationListenPort">Listen Port <code>*</code></label>
|
||||||
<input type="number" class="form-control codeFont" id="addConfigurationListenPort">
|
<input type="number" class="form-control codeFont" id="addConfigurationListenPort" name="addConfigurationListenPort" required>
|
||||||
|
<div id="addConfigurationListenPortFeedback" class="input-feedback"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationAddress">Address <code>(Required)</code></label>
|
<label for="addConfigurationAddress">Address <code>*</code>
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationAddress" placeholder="Ex: 192.168.0.1/24">
|
|
||||||
<div id="addConfigurationAddressFeedback" class="input-feedback">
|
</label>
|
||||||
Please provide a valid city.
|
<input type="text" class="form-control codeFont" id="addConfigurationAddress" placeholder="Ex: 192.168.0.1/24" name="addConfigurationAddress" required>
|
||||||
</div>
|
<div id="addConfigurationAddressFeedback" class="input-feedback"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="">Available IPs for peers</label>
|
<label for=""># of available IPs</label>
|
||||||
<p class="addConfigurationAvailableIPs">N/A</p>
|
<p class="addConfigurationAvailableIPs">N/A</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -139,28 +133,26 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationPreUp">PreUp</label>
|
<label for="addConfigurationPreUp">PreUp</label>
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPreUp">
|
<input type="text" class="form-control codeFont" id="addConfigurationPreUp" name="addConfigurationPreUp">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationPreDown">PreDown</label>
|
<label for="addConfigurationPreDown">PreDown</label>
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPreDown">
|
<input type="text" class="form-control codeFont" id="addConfigurationPreDown" name="addConfigurationPreDown">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationPostUp">PostUp</label>
|
<label for="addConfigurationPostUp">PostUp</label>
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPostUp">
|
<input type="text" class="form-control codeFont" id="addConfigurationPostUp" name="addConfigurationPostUp">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="addConfigurationPostDown">PostDown</label>
|
<label for="addConfigurationPostDown">PostDown</label>
|
||||||
<input type="text" class="form-control codeFont" id="addConfigurationPostDown">
|
<input type="text" class="form-control codeFont" id="addConfigurationPostDown" name="addConfigurationPostDown">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</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>
|
||||||
<button type="button" class="btn btn-primary" id="add_configuration">Add</button>
|
<button type="button" class="btn btn-primary" id="addConfigurationBtn">Add</button>
|
||||||
|
<p class="text-primary addConfigurationStatus d-none"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,9 +104,10 @@ def deletePeers(config_name, delete_keys, cur, db):
|
|||||||
|
|
||||||
def checkJSONAllParameter(required, data):
|
def checkJSONAllParameter(required, data):
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
print("length 0")
|
|
||||||
return False
|
return False
|
||||||
for i in required:
|
for i in required:
|
||||||
if i not in list(data.keys()):
|
if i not in list(data.keys()):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user