diff --git a/src/dashboard.py b/src/dashboard.py index a7ba139..17586d7 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -464,13 +464,41 @@ def check_repeat_allowed_ip(public_key, ip, config_name): return {'status': 'failed', 'msg': 'Peer does not exist'} else: existed_ip = g.cur.execute("SELECT COUNT(*) FROM " + - config_name + " WHERE id != ? AND allowed_ip = ?", (public_key, ip)).fetchone() + config_name + " WHERE id != ? AND allowed_ip LIKE '" + ip + "/%'", (public_key,))\ + .fetchone() if existed_ip[0] != 0: return {'status': 'failed', 'msg': "Allowed IP already taken by another peer."} else: return {'status': 'success'} +def f_available_ips(config_name): + config_interface = read_conf_file_interface(config_name) + if "Address" in config_interface: + existed = [] + conf_address = config_interface['Address'] + address = conf_address.split(',') + for i in address: + add, sub = i.split("/") + existed.append(ipaddress.ip_address(add)) + peers = g.cur.execute("SELECT allowed_ip FROM " + config_name).fetchall() + for i in peers: + add = i[0].split(",") + for k in add: + a, s = k.split("/") + existed.append(ipaddress.ip_address(a)) + available = list(ipaddress.ip_network(address[0], False).hosts()) + for i in existed: + try: + available.remove(i) + except ValueError as e: + pass + available = [str(i) for i in available] + return available + else: + return [] + + """ Flask Functions """ @@ -830,8 +858,6 @@ def get_conf(config_name): conf_data['checked'] = "checked" config.clear() return jsonify(conf_data) - # 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) # Turn on / off a configuration @@ -856,6 +882,64 @@ def switch(config_name): return redirect(request.referrer) +@app.route('/add_peer_bulk/', methods=['POST']) +def add_peer_bulk(config_name): + data = request.get_json() + keys = data['keys'] + endpoint_allowed_ip = data['endpoint_allowed_ip'] + dns_addresses = data['DNS'] + enable_preshared_key = data["enable_preshared_key"] + amount = data['amount'] + if not amount.isdigit() or int(amount) < 1: + return "Amount must be integer larger than 0" + amount = int(amount) + if not check_DNS(dns_addresses): + return "DNS formate is incorrect. Example: 1.1.1.1" + if not check_Allowed_IPs(endpoint_allowed_ip): + return "Endpoint Allowed IPs format is incorrect." + if len(data['MTU']) == 0 or not data['MTU'].isdigit(): + return "MTU format is not correct." + if len(data['keep_alive']) == 0 or not data['keep_alive'].isdigit(): + return "Persistent Keepalive format is not correct." + ips = f_available_ips(config_name) + wg_command = ["wg", "set", config_name] + sql_command = [] + for i in range(amount): + keys[i]['name'] = f"{config_name}_{datetime.now().strftime('%m%d%Y%H%M%S')}_Peer_#_{(i + 1)}" + wg_command.append("peer") + wg_command.append(keys[i]['publicKey']) + keys[i]['allowed_ips'] = ips.pop(0) + if enable_preshared_key: + keys[i]['psk_file'] = f"{keys[i]['name']}.txt" + f = open(keys[i]['psk_file'], "w+") + f.write(keys[i]['presharedKey']) + f.close() + wg_command.append("preshared-key") + wg_command.append(keys[i]['psk_file']) + else: + keys[i]['psk_file'] = "" + wg_command.append("allowed-ips") + wg_command.append(keys[i]['allowed_ips']) + update = ["UPDATE ", config_name, " SET name = '", keys[i]['name'], + "', private_key = '", keys[i]['privateKey'], "', DNS = '", dns_addresses, + "', endpoint_allowed_ip = '", endpoint_allowed_ip, "' WHERE id = '", keys[i]['publicKey'], "'"] + sql_command.append(update) + try: + status = subprocess.check_output(" ".join(wg_command), shell=True, stderr=subprocess.STDOUT) + status = subprocess.check_output("wg-quick save " + config_name, shell=True, stderr=subprocess.STDOUT) + get_all_peers_data(config_name) + if enable_preshared_key: + for i in keys: + os.remove(i['psk_file']) + for i in range(len(sql_command)): + sql_command[i] = "".join(sql_command[i]) + g.cur.executescript("; ".join(sql_command)) + return "true" + except subprocess.CalledProcessError as exc: + return exc.output.strip() + + + # Add peer @app.route('/add_peer/', methods=['POST']) def add_peer(config_name): @@ -865,6 +949,7 @@ def add_peer(config_name): endpoint_allowed_ip = data['endpoint_allowed_ip'] dns_addresses = data['DNS'] enable_preshared_key = data["enable_preshared_key"] + preshared_key = data['preshared_key'] keys = get_conf_peer_key(config_name) if len(public_key) == 0 or len(dns_addresses) == 0 or len(allowed_ips) == 0 or len(endpoint_allowed_ip) == 0: return "Please fill in all required box." @@ -873,7 +958,7 @@ def add_peer(config_name): if public_key in keys: return "Public key already exist." check_dup_ip = g.cur.execute( - "SELECT COUNT(*) FROM " + config_name + " WHERE allowed_ip LIKE '" + allowed_ips + "%'", ) \ + "SELECT COUNT(*) FROM " + config_name + " WHERE allowed_ip LIKE '" + allowed_ips + "/%'", ) \ .fetchone() if check_dup_ip[0] != 0: return "Allowed IP already taken by another peer." @@ -887,11 +972,16 @@ def add_peer(config_name): return "Persistent Keepalive format is not correct." try: if enable_preshared_key: - key = subprocess.check_output("wg genpsk > tmp_psk.txt", shell=True) + now = str(datetime.now().strftime("%m%d%Y%H%M%S")) + f_name = now + "_tmp_psk.txt" + print(f_name) + f = open(f_name, "w+") + f.write(preshared_key) + f.close() status = subprocess.check_output( - f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips} preshared-key tmp_psk.txt", + f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips} preshared-key {f_name}", shell=True, stderr=subprocess.STDOUT) - os.remove("tmp_psk.txt") + os.remove(f_name) elif not enable_preshared_key: status = subprocess.check_output(f"wg set {config_name} peer {public_key} allowed-ips {allowed_ips}", shell=True, stderr=subprocess.STDOUT) @@ -924,6 +1014,7 @@ def remove_peer(config_name): shell=True, stderr=subprocess.STDOUT) sql = "DELETE FROM " + config_name + " WHERE id = ?" g.cur.execute(sql, (delete_key,)) + g.db.commit() return "true" except subprocess.CalledProcessError as exc: return exc.output.strip() @@ -1000,30 +1091,7 @@ def get_peer_name(config_name): # Return available IPs @app.route('/available_ips/', methods=['GET']) def available_ips(config_name): - config_interface = read_conf_file_interface(config_name) - if "Address" in config_interface: - existed = [] - conf_address = config_interface['Address'] - address = conf_address.split(',') - for i in address: - add, sub = i.split("/") - existed.append(ipaddress.ip_address(add)) - peers = g.cur.execute("SELECT allowed_ip FROM " + config_name).fetchall() - for i in peers: - add = i[0].split(",") - for k in add: - a, s = k.split("/") - existed.append(ipaddress.ip_address(a)) - available = list(ipaddress.ip_network(address[0], False).hosts()) - for i in existed: - try: - available.remove(i) - except ValueError as e: - pass - available = [str(i) for i in available] - return jsonify(available) - else: - return jsonify([]) + return jsonify(f_available_ips(config_name)) # Generate a private key diff --git a/src/static/.DS_Store b/src/static/.DS_Store index 5008ddf..ba3b77f 100644 Binary files a/src/static/.DS_Store and b/src/static/.DS_Store differ diff --git a/src/static/css/dashboard.css b/src/static/css/dashboard.css index f7f8377..a1cac82 100644 --- a/src/static/css/dashboard.css +++ b/src/static/css/dashboard.css @@ -90,6 +90,14 @@ body { right: 1rem; } +.form-control{ + transition: all 0.2s ease-in-out; +} + +.form-control:disabled{ + cursor: not-allowed; +} + .navbar .form-control { padding: .75rem 1rem; border-width: 0; diff --git a/src/static/css/dashboard.min.css b/src/static/css/dashboard.min.css index fff2c94..7c68d69 100644 --- a/src/static/css/dashboard.min.css +++ b/src/static/css/dashboard.min.css @@ -1 +1 @@ -@-webkit-keyframes rotating{0%{-webkit-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotating{0%{-ms-transform:rotate(0deg);-moz-transform:rotate(0deg);-webkit-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}to{-ms-transform:rotate(360deg);-moz-transform:rotate(360deg);-webkit-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading{0%,to{background-color:#dfdfdf}50%{background-color:#adadad}}@-moz-keyframes loading{0%,to{background-color:#dfdfdf}50%{background-color:#adadad}}body{font-size:.875rem}.feather{width:16px;height:16px;vertical-align:text-bottom}.sidebar{position:fixed;top:0;bottom:0;left:0;z-index:100;padding:48px 0 0;box-shadow:inset -1px 0 0 rgba(0,0,0,.1)}.sidebar-sticky{position:relative;top:0;height:calc(100vh - 48px);padding-top:.5rem;overflow-x:hidden;overflow-y:auto}@supports ((position:-webkit-sticky) or (position:sticky)){.sidebar-sticky{position:-webkit-sticky;position:sticky}}.sidebar .nav-link{font-weight:500;color:#333;transition:.2s cubic-bezier(.82,-.07,0,1.01)}.nav-link:hover{padding-left:30px}.sidebar .nav-link .feather{margin-right:4px;color:#999}.sidebar .nav-link.active{color:#007bff}.sidebar .nav-link.active .feather,.sidebar .nav-link:hover .feather{color:inherit}.sidebar-heading{font-size:.75rem;text-transform:uppercase}.navbar-brand{padding-top:.75rem;padding-bottom:.75rem;font-size:1rem;background-color:rgba(0,0,0,.25);box-shadow:inset -1px 0 0 rgba(0,0,0,.25)}.navbar .navbar-toggler{top:.25rem;right:1rem}.navbar .form-control{padding:.75rem 1rem;border-width:0;border-radius:0}.form-control-dark{color:#fff;background-color:rgba(255,255,255,.1);border-color:rgba(255,255,255,.1)}.form-control-dark:focus{border-color:transparent;box-shadow:0 0 0 3px rgba(255,255,255,.25)}.dot{width:10px;height:10px;border-radius:50px;display:inline-block;margin-left:10px}.dot-running{background-color:#28a745!important;box-shadow:0 0 0 .2rem #28a74545}.h6-dot-running{margin-left:.3rem}.dot-stopped{background-color:#6c757d!important}.card-running{border-color:#28a745}.info h6{line-break:anywhere;transition:.2s ease-in-out}.info .row .col-sm{display:flex;flex-direction:column}.info .row .col-sm small{display:flex}.info .row .col-sm small strong:last-child(1){margin-left:auto!important}.btn-control{border:0!important;padding:0 1rem 0 0}.btn-control:active,.btn-control:focus{background-color:transparent!important;border:0!important;box-shadow:none}.share_peer_btn_group .btn-control{padding:0 0 0 1rem}.btn-control:hover{background:#fff}.btn-delete-peer:hover{color:#dc3545}.btn-setting-peer:hover{color:#007bff}.btn-download-peer:hover{color:#17a2b8}.login-container{padding:2rem}@media (max-width:992px){.card-col{margin-bottom:1rem}}.switch{font-size:2rem}.switch:hover{text-decoration:none}.btn-group-label:hover{color:#007bff;border-color:#007bff;background:#fff}@media (max-width:768px){.peer_data_group{text-align:left}}.index-switch{text-align:right}main{margin-bottom:3rem}.peer_list{margin-bottom:7rem}@media (max-width:768px){.add_btn{bottom:1.5rem!important}.peer_list{margin-bottom:4rem!important}}.add_btn{position:fixed;bottom:3rem;right:2rem;z-index:99;border-radius:100px!important;padding:10px 20px;box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}.rotating::before{-webkit-animation:rotating .75s linear infinite;-moz-animation:rotating .75s linear infinite;-ms-animation:rotating .75s linear infinite;-o-animation:rotating .75s linear infinite;animation:rotating .75s linear infinite}.peer_private_key_textbox_switch{position:absolute;right:2rem;transform:translateY(-28px);font-size:1.2rem;cursor:pointer}#peer_private_key_textbox,#private_key,#public_key{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.progress-bar{transition:.3s ease-in-out}.key{transition:.2s ease-in-out;cursor:pointer}.key:hover{color:#007bff}.card,.form-control{border-radius:10px}.peer_list .card .button-group{height:22px}.btn{border-radius:8px}.modal-content{border-radius:10px}.tooltip-inner{font-size:.8rem}#conf_status_btn,.conf_card{transition:.2s ease-in-out}.conf_card:hover{border-color:#007bff;cursor:pointer}.info_loading{animation:loading 2s infinite ease-in-out;border-radius:5px;height:19px;transition:.3s ease-in-out}#conf_status_btn.info_loading{height:38px;border-radius:5px;animation:loading 3s infinite ease-in-out}#qrcode_img img{width:100%}#selected_ip_list .badge{margin:.1rem}#add_modal.ip_modal_open{transition:filter .2s ease-in-out;filter:brightness(.5)} \ No newline at end of file +@-webkit-keyframes rotating{0%{-webkit-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotating{0%{-ms-transform:rotate(0deg);-moz-transform:rotate(0deg);-webkit-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}to{-ms-transform:rotate(360deg);-moz-transform:rotate(360deg);-webkit-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading{0%,to{background-color:#dfdfdf}50%{background-color:#adadad}}@-moz-keyframes loading{0%,to{background-color:#dfdfdf}50%{background-color:#adadad}}body{font-size:.875rem}.feather{width:16px;height:16px;vertical-align:text-bottom}.sidebar{position:fixed;top:0;bottom:0;left:0;z-index:100;padding:48px 0 0;box-shadow:inset -1px 0 0 rgba(0,0,0,.1)}.sidebar-sticky{position:relative;top:0;height:calc(100vh - 48px);padding-top:.5rem;overflow-x:hidden;overflow-y:auto}@supports ((position:-webkit-sticky) or (position:sticky)){.sidebar-sticky{position:-webkit-sticky;position:sticky}}.sidebar .nav-link{font-weight:500;color:#333;transition:.2s cubic-bezier(.82,-.07,0,1.01)}.nav-link:hover{padding-left:30px}.sidebar .nav-link .feather{margin-right:4px;color:#999}.sidebar .nav-link.active{color:#007bff}.sidebar .nav-link.active .feather,.sidebar .nav-link:hover .feather{color:inherit}.sidebar-heading{font-size:.75rem;text-transform:uppercase}.navbar-brand{padding-top:.75rem;padding-bottom:.75rem;font-size:1rem;background-color:rgba(0,0,0,.25);box-shadow:inset -1px 0 0 rgba(0,0,0,.25)}.navbar .navbar-toggler{top:.25rem;right:1rem}.form-control{transition:all .2s ease-in-out}.form-control:disabled{cursor:not-allowed}.navbar .form-control{padding:.75rem 1rem;border-width:0;border-radius:0}.form-control-dark{color:#fff;background-color:rgba(255,255,255,.1);border-color:rgba(255,255,255,.1)}.form-control-dark:focus{border-color:transparent;box-shadow:0 0 0 3px rgba(255,255,255,.25)}.dot{width:10px;height:10px;border-radius:50px;display:inline-block;margin-left:10px}.dot-running{background-color:#28a745!important;box-shadow:0 0 0 .2rem #28a74545}.h6-dot-running{margin-left:.3rem}.dot-stopped{background-color:#6c757d!important}.card-running{border-color:#28a745}.info h6{line-break:anywhere;transition:.2s ease-in-out}.info .row .col-sm{display:flex;flex-direction:column}.info .row .col-sm small{display:flex}.info .row .col-sm small strong:last-child(1){margin-left:auto!important}.btn-control{border:0!important;padding:0 1rem 0 0}.btn-control:active,.btn-control:focus{background-color:transparent!important;border:0!important;box-shadow:none}.share_peer_btn_group .btn-control{padding:0 0 0 1rem}.btn-control:hover{background:#fff}.btn-delete-peer:hover{color:#dc3545}.btn-setting-peer:hover{color:#007bff}.btn-download-peer:hover{color:#17a2b8}.login-container{padding:2rem}@media (max-width:992px){.card-col{margin-bottom:1rem}}.switch{font-size:2rem}.switch:hover{text-decoration:none}.btn-group-label:hover{color:#007bff;border-color:#007bff;background:#fff}@media (max-width:768px){.peer_data_group{text-align:left}}.index-switch{text-align:right}main{margin-bottom:3rem}.peer_list{margin-bottom:7rem}@media (max-width:768px){.add_btn{bottom:1.5rem!important}.peer_list{margin-bottom:4rem!important}}.add_btn{position:fixed;bottom:3rem;right:2rem;z-index:99;border-radius:100px!important;padding:10px 20px;box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}.rotating::before{-webkit-animation:rotating .75s linear infinite;-moz-animation:rotating .75s linear infinite;-ms-animation:rotating .75s linear infinite;-o-animation:rotating .75s linear infinite;animation:rotating .75s linear infinite}.peer_private_key_textbox_switch{position:absolute;right:2rem;transform:translateY(-28px);font-size:1.2rem;cursor:pointer}#peer_private_key_textbox,#private_key,#public_key{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.progress-bar{transition:.3s ease-in-out}.key{transition:.2s ease-in-out;cursor:pointer}.key:hover{color:#007bff}.card,.form-control{border-radius:10px}.peer_list .card .button-group{height:22px}.btn{border-radius:8px}.modal-content{border-radius:10px}.tooltip-inner{font-size:.8rem}#conf_status_btn,.conf_card{transition:.2s ease-in-out}.conf_card:hover{border-color:#007bff;cursor:pointer}.info_loading{animation:loading 2s infinite ease-in-out;border-radius:5px;height:19px;transition:.3s ease-in-out}#conf_status_btn.info_loading{height:38px;border-radius:5px;animation:loading 3s infinite ease-in-out}#qrcode_img img{width:100%}#selected_ip_list .badge{margin:.1rem}#add_modal.ip_modal_open{transition:filter .2s ease-in-out;filter:brightness(.5)} \ No newline at end of file diff --git a/src/static/js/configuration.js b/src/static/js/configuration.js index 3e02930..3bee908 100644 --- a/src/static/js/configuration.js +++ b/src/static/js/configuration.js @@ -1,4 +1,5 @@ $("[data-toggle='tooltip']").tooltip() +$("[data-toggle='popover']").popover() let $body = $("body"); let $progress_bar = $(".progress-bar"); let available_ips = []; @@ -74,44 +75,21 @@ $body.on("click", ".switch", function (){ * Generate Private and Public key for a new peer */ 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"); - }); -} - -/** - * Generate public for existing peer - */ -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).removeClass("d-none"); - }else{ - $("#add_peer_alert").addClass("d-none"); - } - $("#public_key").val(res.data); - $("#re_generate_key i").removeClass("rotating"); - }); + let keys = wireguard.generateKeypair(); + $("#private_key").val(keys.privateKey); + $("#public_key").val(keys.publicKey); + $("#add_peer_alert").addClass("d-none"); + $("#re_generate_key i").removeClass("rotating"); + $("#enable_preshare_key").val(keys.presharedKey); } /** * Generate Public key when private got change */ $("#private_key").on("change",function(){ - if ($(this).val().length > 0){ + if ($(this).val().length === 44){ $("#re_generate_key i").addClass("rotating"); - generate_public_key(); + $("#public_key").val(wireguard.generatePublicKey($("#private_key").val())); }else{ $("#public_key").removeAttr("disabled").val(""); } @@ -241,63 +219,130 @@ function clean_ip(val){ return clean_ip.filter(Boolean).join(","); } -$save_peer.on("click",function(){ - let $public_key = $("#public_key"); - let $private_key = $("#private_key"); - let $allowed_ips = $("#allowed_ips"); - $allowed_ips.val(clean_ip($allowed_ips.val())); +let bulk_add_peers = () => { + $save_peer.attr("disabled","disabled"); + $save_peer.html("Adding..."); + let $new_add_DNS = $("#new_add_DNS"); $new_add_DNS.val(clean_ip($new_add_DNS.val())); let $new_add_endpoint_allowed_ip = $("#new_add_endpoint_allowed_ip"); - $new_add_endpoint_allowed_ip.val(clean_ip($new_add_endpoint_allowed_ip.val())); - let $new_add_name = $("#new_add_name"); + $new_add_endpoint_allowed_ip.val(clean_ip($new_add_endpoint_allowed_ip.val())); let $new_add_MTU = $("#new_add_MTU"); let $new_add_keep_alive = $("#new_add_keep_alive"); let $enable_preshare_key = $("#enable_preshare_key"); - let p_key = $public_key.val() - $(this).attr("disabled","disabled"); - $(this).html("Saving..."); - if ($allowed_ips.val() !== "" && $public_key.val() !== "" && $new_add_DNS.val() !== "" && $new_add_endpoint_allowed_ip.val() !== ""){ - let conf = $(this).attr('conf_id'); - let data_list = [$private_key, $allowed_ips, $new_add_name, $new_add_DNS, $new_add_endpoint_allowed_ip,$new_add_MTU, $new_add_keep_alive]; - data_list.forEach((ele) => ele.attr("disabled", "disabled")); - $.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": $new_add_DNS.val(), - "endpoint_allowed_ip": $new_add_endpoint_allowed_ip.val(), - "MTU": $new_add_MTU.val(), - "keep_alive": $new_add_keep_alive.val(), - "enable_preshared_key": $enable_preshare_key.prop("checked"), - }), - success: function (response){ - if(response !== "true"){ - $("#add_peer_alert").html(response).removeClass("d-none"); - data_list.forEach((ele) => ele.removeAttr("disabled")); - $save_peer.removeAttr("disabled").html("Save"); + let $new_add_amount = $("#new_add_amount"); + let data_list = [$new_add_DNS, $new_add_endpoint_allowed_ip,$new_add_MTU, $new_add_keep_alive]; + if ($new_add_amount.val() > 0){ + if ($new_add_DNS.val() !== "" && $new_add_endpoint_allowed_ip.val() !== ""){ + let conf = $save_peer.attr('conf_id'); + let keys = []; + for (let i = 0; i < $new_add_amount.val(); i++) keys.push(wireguard.generateKeypair()); + $.ajax({ + method: "POST", + url: "/add_peer_bulk/"+conf, + headers:{ + "Content-Type": "application/json" + }, + data: JSON.stringify({ + "DNS": $new_add_DNS.val(), + "endpoint_allowed_ip": $new_add_endpoint_allowed_ip.val(), + "MTU": $new_add_MTU.val(), + "keep_alive": $new_add_keep_alive.val(), + "enable_preshared_key": $enable_preshare_key.prop("checked"), + "keys": keys, + "amount": $new_add_amount.val() + }), + success: function (response){ + if(response !== "true"){ + $("#add_peer_alert").html(response).removeClass("d-none"); + data_list.forEach((ele) => ele.removeAttr("disabled")); + $save_peer.removeAttr("disabled").html("Save"); + } + else{ + load_data(""); + data_list.forEach((ele) => ele.removeAttr("disabled")); + $("#add_peer_form").trigger("reset"); + $save_peer.removeAttr("disabled").html("Save"); + showToast($new_add_amount.val()+"peers added successful!"); + addModal.toggle(); + } } - else{ - load_data(""); - data_list.forEach((ele) => ele.removeAttr("disabled")); - $("#add_peer_form").trigger("reset"); - $save_peer.removeAttr("disabled").html("Save"); - showToast("Add peer successful!"); - addModal.toggle(); - } - } - }); + }) + }else{ + $("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none"); + $save_peer.removeAttr("disabled"); + $save_peer.html("Add"); + } }else{ - $("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none"); - $(this).removeAttr("disabled"); - $(this).html("Save"); + $("#add_peer_alert").html("Please enter 1 or more amount.").removeClass("d-none"); + $save_peer.removeAttr("disabled"); + $save_peer.html("Add"); + } +} + + +$save_peer.on("click",function(){ + let $bulk_add = $("#bulk_add"); + if ($bulk_add.prop("checked")){ + bulk_add_peers() + }else { + let $public_key = $("#public_key"); + let $private_key = $("#private_key"); + let $allowed_ips = $("#allowed_ips"); + $allowed_ips.val(clean_ip($allowed_ips.val())); + let $new_add_DNS = $("#new_add_DNS"); + $new_add_DNS.val(clean_ip($new_add_DNS.val())); + let $new_add_endpoint_allowed_ip = $("#new_add_endpoint_allowed_ip"); + $new_add_endpoint_allowed_ip.val(clean_ip($new_add_endpoint_allowed_ip.val())); + let $new_add_name = $("#new_add_name"); + let $new_add_MTU = $("#new_add_MTU"); + let $new_add_keep_alive = $("#new_add_keep_alive"); + let $enable_preshare_key = $("#enable_preshare_key"); + $(this).attr("disabled","disabled"); + $(this).html("Adding..."); + if ($allowed_ips.val() !== "" && $public_key.val() !== "" && $new_add_DNS.val() !== "" && $new_add_endpoint_allowed_ip.val() !== ""){ + let conf = $(this).attr('conf_id'); + let data_list = [$private_key, $allowed_ips, $new_add_name, $new_add_DNS, $new_add_endpoint_allowed_ip,$new_add_MTU, $new_add_keep_alive]; + data_list.forEach((ele) => ele.attr("disabled", "disabled")); + $.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": $new_add_DNS.val(), + "endpoint_allowed_ip": $new_add_endpoint_allowed_ip.val(), + "MTU": $new_add_MTU.val(), + "keep_alive": $new_add_keep_alive.val(), + "enable_preshared_key": $enable_preshare_key.prop("checked"), + "preshared_key": $enable_preshare_key.val() + }), + success: function (response){ + if(response !== "true"){ + $("#add_peer_alert").html(response).removeClass("d-none"); + data_list.forEach((ele) => ele.removeAttr("disabled")); + $save_peer.removeAttr("disabled").html("Save"); + } + else{ + load_data(""); + data_list.forEach((ele) => ele.removeAttr("disabled")); + $("#add_peer_form").trigger("reset"); + $save_peer.removeAttr("disabled").html("Save"); + showToast("Add peer successful!"); + addModal.toggle(); + } + } + }); + }else{ + $("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none"); + $(this).removeAttr("disabled"); + $(this).html("Add"); + } } }); @@ -591,4 +636,23 @@ $body.on("click", ".display_mode", function(){ } } }); -}); \ No newline at end of file +}); + +$("#bulk_add").on("change", function (){ + let hide = $(".non-bulk").find("input"); + let amount = $("#new_add_amount"); + if ($(this).prop("checked") === true){ + for(let i = 0; i < hide.length; i++){ + $(hide[i]).attr("disabled", "disabled"); + } + amount.removeAttr("disabled"); + } + else{ + for(let i = 0; i < hide.length; i++){ + if ($(hide[i]).attr('id') !== "public_key"){ + $(hide[i]).removeAttr("disabled"); + } + } + amount.attr("disabled", "disabled"); + } +}) \ No newline at end of file diff --git a/src/static/js/configuration.min.js b/src/static/js/configuration.min.js index cf30794..438a7cb 100644 --- a/src/static/js/configuration.min.js +++ b/src/static/js/configuration.min.js @@ -1 +1 @@ -$("[data-toggle='tooltip']").tooltip();let $body=$("body");let $progress_bar=$(".progress-bar");let available_ips=[];let $save_peer=$("#save_peer");$(".add_btn").on("click",function(){addModal.toggle()});function roundN(value,digits){let tenToN=10**digits;return Math.round(value*tenToN)/tenToN}function startProgressBar(){$progress_bar.css("width","0%").css("opacity","100").css("background","rgb(255,69,69)").css("background","linear-gradient(145deg, rgba(255,69,69,1) 0%, rgba(0,115,186,1) 100%)").css("width","25%");setTimeout(function(){stillLoadingProgressBar()},300)}function stillLoadingProgressBar(){$progress_bar.css("transition","3s ease-in-out").css("width","75%")}function endProgressBar(){$progress_bar.css("transition","0.3s ease-in-out").css("width","100%");setTimeout(function(){$progress_bar.css("opacity","0")},250)}function showToast(msg){$("#alertToast").toast("show");$("#alertToast .toast-body").html(msg)}$body.on("click",".switch",function(){$(this).siblings($(".spinner-border")).css("display","inline-block");$(this).remove();location.replace("/switch/"+$(this).attr("id"))});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).removeClass("d-none")}else{$("#add_peer_alert").addClass("d-none")}$("#public_key").val(res.data);$("#re_generate_key i").removeClass("rotating")})}$("#private_key").on("change",function(){if($(this).val().length>0){$("#re_generate_key i").addClass("rotating");generate_public_key()}else{$("#public_key").removeAttr("disabled").val("")}});function trigger_ip(ip){let $ip_ele=$(".available-ip-item[data-ip='"+ip+"']");if($ip_ele.html()){if($ip_ele.hasClass("active")){$ip_ele.removeClass("active");$("#selected_ip_list .badge[data-ip='"+ip+"']").remove()}else{$ip_ele.addClass("active");$("#selected_ip_list").append(''+ip+"")}}}function get_available_ip(){$.ajax({url:"/available_ips/"+$save_peer.attr("conf_id"),method:"GET"}).done(function(res){available_ips=res;let $list_group=$("#available_ip_modal .modal-body .list-group");$list_group.html("");$("#allowed_ips").val(available_ips[0]);available_ips.forEach(ip=>$list_group.append(''+ip+""))})}$("#available_ip_modal").on("show.bs.modal",()=>{$("#add_modal").addClass("ip_modal_open")}).on("hidden.bs.modal",function(){$("#add_modal").removeClass("ip_modal_open");let ips=[];let $selected_ip_list=$("#selected_ip_list");$selected_ip_list.children().each(function(){ips.push($(this).data("ip"))});ips.forEach(ele=>trigger_ip(ele))});$body.on("click",".available-ip-badge",function(){$(".available-ip-item[data-ip='"+$(this).data("ip")+"']").removeClass("active");$(this).remove()});$body.on("click",".available-ip-item",function(){trigger_ip($(this).data("ip"))});let $ipModal=new bootstrap.Modal(document.getElementById("available_ip_modal"),{keyboard:false});$("#search_available_ip").on("click",function(){$ipModal.toggle();let $allowed_ips=$("#allowed_ips");if($allowed_ips.val().length>0){let s=$allowed_ips.val().split(",");for(let i=0;i{$ipModal.toggle();let ips=[];let $selected_ip_list=$("#selected_ip_list");$selected_ip_list.children().each(function(){ips.push($(this).data("ip"))});$("#allowed_ips").val(ips.join(", "));ips.forEach(ele=>trigger_ip(ele))});$("#allowed_ips").on("keyup",function(){let s=clean_ip($(this).val());s=s.split(",");if(available_ips.includes(s[s.length-1])){$("#allowed_ips_indicator").removeClass().addClass("text-success").html('')}else{$("#allowed_ips_indicator").removeClass().addClass("text-warning").html('')}});$("#add_modal").on("show.bs.modal",function(event){generate_key();get_available_ip()}).on("hide.bs.modal",function(){$("#allowed_ips_indicator").html("")});$("#re_generate_key").on("click",function(){$("#public_key").attr("disabled","disabled");$("#re_generate_key i").addClass("rotating");generate_key()});let addModal=new bootstrap.Modal(document.getElementById("add_modal"),{keyboard:false});function clean_ip(val){let clean_ip=val.split(",");for(let i=0;iele.attr("disabled","disabled"));$.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:$new_add_DNS.val(),endpoint_allowed_ip:$new_add_endpoint_allowed_ip.val(),MTU:$new_add_MTU.val(),keep_alive:$new_add_keep_alive.val(),enable_preshared_key:$enable_preshare_key.prop("checked")}),success:function(response){if(response!=="true"){$("#add_peer_alert").html(response).removeClass("d-none");data_list.forEach(ele=>ele.removeAttr("disabled"));$save_peer.removeAttr("disabled").html("Save")}else{load_data("");data_list.forEach(ele=>ele.removeAttr("disabled"));$("#add_peer_form").trigger("reset");$save_peer.removeAttr("disabled").html("Save");showToast("Add peer successful!");addModal.toggle()}}})}else{$("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none");$(this).removeAttr("disabled");$(this).html("Save")}});let qrcodeModal=new bootstrap.Modal(document.getElementById("qrcode_modal"),{keyboard:false});$body.on("click",".btn-qrcode-peer",function(){let src=$(this).attr("img_src");$.ajax({url:src,method:"GET"}).done(function(res){$("#qrcode_img").attr("src",res);qrcodeModal.toggle()})});let deleteModal=new bootstrap.Modal(document.getElementById("delete_modal"),{keyboard:false});$body.on("click",".btn-delete-peer",function(){let peer_id=$(this).attr("id");$("#delete_peer").attr("peer_id",peer_id);deleteModal.toggle()});$("#delete_peer").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Deleting...");let peer_id=$(this).attr("peer_id");let 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()).removeClass("d-none")}else{deleteModal.toggle();load_data($("#search_peer_textbox").val());$("#alertToast").toast("show");$("#alertToast .toast-body").html("Peer deleted!");$("#delete_peer").removeAttr("disabled").html("Delete")}}})});let settingModal=new bootstrap.Modal(document.getElementById("setting_modal"),{keyboard:false});$body.on("click",".btn-setting-peer",function(){startProgressBar();let 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(response.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 #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);$("#setting_modal #peer_preshared_key_textbox").val(response.preshared_key);settingModal.toggle();endProgressBar()}})});$("#setting_modal").on("hidden.bs.modal",function(event){$("#setting_peer_alert").addClass("d-none")});$("#peer_private_key_textbox").on("change",function(){let $save_peer_setting=$("#save_peer_setting");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.status).removeClass("d-none")}else{$("#setting_peer_alert").addClass("d-none")}})}});$("#save_peer_setting").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Saving...");let $peer_DNS_textbox=$("#peer_DNS_textbox");let $peer_allowed_ip_textbox=$("#peer_allowed_ip_textbox");let $peer_endpoint_allowed_ips=$("#peer_endpoint_allowed_ips");let $peer_name_textbox=$("#peer_name_textbox");let $peer_private_key_textbox=$("#peer_private_key_textbox");let $peer_preshared_key_textbox=$("#peer_preshared_key_textbox");let $peer_mtu=$("#peer_mtu");let $peer_keep_alive=$("#peer_keep_alive");if($peer_DNS_textbox.val()!==""&&$peer_allowed_ip_textbox.val()!==""&&$peer_endpoint_allowed_ips.val()!==""){let peer_id=$(this).attr("peer_id");let conf_id=$(this).attr("conf_id");let data_list=[$peer_name_textbox,$peer_DNS_textbox,$peer_private_key_textbox,$peer_preshared_key_textbox,$peer_allowed_ip_textbox,$peer_endpoint_allowed_ips,$peer_mtu,$peer_keep_alive];data_list.forEach(ele=>ele.attr("disabled","disabled"));$.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(),endpoint_allowed_ip:$peer_endpoint_allowed_ips.val(),MTU:$peer_mtu.val(),keep_alive:$peer_keep_alive.val(),preshared_key:$peer_preshared_key_textbox.val()}),success:function(response){if(response.status==="failed"){$("#setting_peer_alert").html(response.msg).removeClass("d-none")}else{settingModal.toggle();load_data($("#search_peer_textbox").val());$("#alertToast").toast("show");$("#alertToast .toast-body").html("Peer Saved!")}$("#save_peer_setting").removeAttr("disabled").html("Save");data_list.forEach(ele=>ele.removeAttr("disabled"))}})}else{$("#setting_peer_alert").html("Please fill in all required box.").removeClass("d-none");$("#save_peer_setting").removeAttr("disabled").html("Save")}});$(".peer_private_key_textbox_switch").on("click",function(){let $peer_private_key_textbox=$("#peer_private_key_textbox");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)});let typingTimer;let doneTypingInterval=200;let $input=$("#search_peer_textbox");$input.on("keyup",function(){clearTimeout(typingTimer);typingTimer=setTimeout(doneTyping,doneTypingInterval)});$input.on("keydown",function(){clearTimeout(typingTimer)});function doneTyping(){load_data($input.val())}$body.on("change","#sort_by_dropdown",function(){$.ajax({method:"POST",data:JSON.stringify({sort:$("#sort_by_dropdown option:selected").val()}),headers:{"Content-Type":"application/json"},url:"/update_dashboard_sort",success:function(res){load_data($("#search_peer_textbox").val())}})});$body.on("mouseenter",".key",function(){let label=$(this).parent().siblings().children()[1];label.style.opacity="100"}).on("mouseout",".key",function(){let label=$(this).parent().siblings().children()[1];label.style.opacity="0";setTimeout(function(){label.innerHTML="CLICK TO COPY"},200)}).on("click",".key",function(){var label=$(this).parent().siblings().children()[1];copyToClipboard($(this));label.innerHTML="COPIED!"});function copyToClipboard(element){let $temp=$("");$body.append($temp);$temp.val($(element).text()).trigger("select");document.execCommand("copy");$temp.remove()}$body.on("click",".update_interval",function(){let prev=$(".interval-btn-group.active button");$(".interval-btn-group button").removeClass("active");let _new=$(this);_new.addClass("active");let interval=$(this).data("refresh-interval");$.ajax({method:"POST",data:"interval="+$(this).data("refresh-interval"),url:"/update_dashboard_refresh_interval",success:function(res){if(res==="true"){load_interval=interval;clearInterval(load_timeout);load_timeout=setInterval(function(){load_data($("#search_peer_textbox").val())},interval);showToast("Refresh Interval set to "+Math.round(interval/1e3)+" seconds")}else{$(".interval-btn-group button").removeClass("active");$('.interval-btn-group button[data-refresh-interval="'+load_interval+'"]').addClass("active");showToast("Refresh Interval set unsuccessful")}}})});$body.on("click",".refresh",function(){load_data($("#search_peer_textbox").val())});$body.on("click",".display_mode",function(){$(".display-btn-group button").removeClass("active");$(this).addClass("active");let display_mode=$(this).data("display-mode");$.ajax({method:"GET",url:"/switch_display_mode/"+$(this).data("display-mode"),success:function(res){if(res==="true"){if(display_mode==="list"){Array($(".peer_list").children()).forEach(function(child){$(child).removeClass().addClass("col-12")});showToast("Displaying as List")}else{Array($(".peer_list").children()).forEach(function(child){$(child).removeClass().addClass("col-sm-6 col-lg-4")});showToast("Displaying as Grids")}}}})}); \ No newline at end of file +$("[data-toggle='tooltip']").tooltip();$("[data-toggle='popover']").popover();let $body=$("body");let $progress_bar=$(".progress-bar");let available_ips=[];let $save_peer=$("#save_peer");$(".add_btn").on("click",function(){addModal.toggle()});function roundN(value,digits){let tenToN=10**digits;return Math.round(value*tenToN)/tenToN}function startProgressBar(){$progress_bar.css("width","0%").css("opacity","100").css("background","rgb(255,69,69)").css("background","linear-gradient(145deg, rgba(255,69,69,1) 0%, rgba(0,115,186,1) 100%)").css("width","25%");setTimeout(function(){stillLoadingProgressBar()},300)}function stillLoadingProgressBar(){$progress_bar.css("transition","3s ease-in-out").css("width","75%")}function endProgressBar(){$progress_bar.css("transition","0.3s ease-in-out").css("width","100%");setTimeout(function(){$progress_bar.css("opacity","0")},250)}function showToast(msg){$("#alertToast").toast("show");$("#alertToast .toast-body").html(msg)}$body.on("click",".switch",function(){$(this).siblings($(".spinner-border")).css("display","inline-block");$(this).remove();location.replace("/switch/"+$(this).attr("id"))});function generate_key(){let keys=wireguard.generateKeypair();$("#private_key").val(keys.privateKey);$("#public_key").val(keys.publicKey);$("#add_peer_alert").addClass("d-none");$("#re_generate_key i").removeClass("rotating");$("#enable_preshare_key").val(keys.presharedKey)}$("#private_key").on("change",function(){if($(this).val().length===44){$("#re_generate_key i").addClass("rotating");$("#public_key").val(wireguard.generatePublicKey($("#private_key").val()))}else{$("#public_key").removeAttr("disabled").val("")}});function trigger_ip(ip){let $ip_ele=$(".available-ip-item[data-ip='"+ip+"']");if($ip_ele.html()){if($ip_ele.hasClass("active")){$ip_ele.removeClass("active");$("#selected_ip_list .badge[data-ip='"+ip+"']").remove()}else{$ip_ele.addClass("active");$("#selected_ip_list").append(''+ip+"")}}}function get_available_ip(){$.ajax({url:"/available_ips/"+$save_peer.attr("conf_id"),method:"GET"}).done(function(res){available_ips=res;let $list_group=$("#available_ip_modal .modal-body .list-group");$list_group.html("");$("#allowed_ips").val(available_ips[0]);available_ips.forEach(ip=>$list_group.append(''+ip+""))})}$("#available_ip_modal").on("show.bs.modal",()=>{$("#add_modal").addClass("ip_modal_open")}).on("hidden.bs.modal",function(){$("#add_modal").removeClass("ip_modal_open");let ips=[];let $selected_ip_list=$("#selected_ip_list");$selected_ip_list.children().each(function(){ips.push($(this).data("ip"))});ips.forEach(ele=>trigger_ip(ele))});$body.on("click",".available-ip-badge",function(){$(".available-ip-item[data-ip='"+$(this).data("ip")+"']").removeClass("active");$(this).remove()});$body.on("click",".available-ip-item",function(){trigger_ip($(this).data("ip"))});let $ipModal=new bootstrap.Modal(document.getElementById("available_ip_modal"),{keyboard:false});$("#search_available_ip").on("click",function(){$ipModal.toggle();let $allowed_ips=$("#allowed_ips");if($allowed_ips.val().length>0){let s=$allowed_ips.val().split(",");for(let i=0;i{$ipModal.toggle();let ips=[];let $selected_ip_list=$("#selected_ip_list");$selected_ip_list.children().each(function(){ips.push($(this).data("ip"))});$("#allowed_ips").val(ips.join(", "));ips.forEach(ele=>trigger_ip(ele))});$("#allowed_ips").on("keyup",function(){let s=clean_ip($(this).val());s=s.split(",");if(available_ips.includes(s[s.length-1])){$("#allowed_ips_indicator").removeClass().addClass("text-success").html('')}else{$("#allowed_ips_indicator").removeClass().addClass("text-warning").html('')}});$("#add_modal").on("show.bs.modal",function(event){generate_key();get_available_ip()}).on("hide.bs.modal",function(){$("#allowed_ips_indicator").html("")});$("#re_generate_key").on("click",function(){$("#public_key").attr("disabled","disabled");$("#re_generate_key i").addClass("rotating");generate_key()});let addModal=new bootstrap.Modal(document.getElementById("add_modal"),{keyboard:false});function clean_ip(val){let clean_ip=val.split(",");for(let i=0;i{$save_peer.attr("disabled","disabled");$save_peer.html("Adding...");let $new_add_DNS=$("#new_add_DNS");$new_add_DNS.val(clean_ip($new_add_DNS.val()));let $new_add_endpoint_allowed_ip=$("#new_add_endpoint_allowed_ip");$new_add_endpoint_allowed_ip.val(clean_ip($new_add_endpoint_allowed_ip.val()));let $new_add_MTU=$("#new_add_MTU");let $new_add_keep_alive=$("#new_add_keep_alive");let $enable_preshare_key=$("#enable_preshare_key");let $new_add_amount=$("#new_add_amount");let data_list=[$new_add_DNS,$new_add_endpoint_allowed_ip,$new_add_MTU,$new_add_keep_alive];if($new_add_amount.val()>0){if($new_add_DNS.val()!==""&&$new_add_endpoint_allowed_ip.val()!==""){let conf=$save_peer.attr("conf_id");let keys=[];for(let i=0;i<$new_add_amount.val();i++)keys.push(wireguard.generateKeypair());$.ajax({method:"POST",url:"/add_peer_bulk/"+conf,headers:{"Content-Type":"application/json"},data:JSON.stringify({DNS:$new_add_DNS.val(),endpoint_allowed_ip:$new_add_endpoint_allowed_ip.val(),MTU:$new_add_MTU.val(),keep_alive:$new_add_keep_alive.val(),enable_preshared_key:$enable_preshare_key.prop("checked"),keys:keys,amount:$new_add_amount.val()}),success:function(response){if(response!=="true"){$("#add_peer_alert").html(response).removeClass("d-none");data_list.forEach(ele=>ele.removeAttr("disabled"));$save_peer.removeAttr("disabled").html("Save")}else{load_data("");data_list.forEach(ele=>ele.removeAttr("disabled"));$("#add_peer_form").trigger("reset");$save_peer.removeAttr("disabled").html("Save");showToast($new_add_amount.val()+"peers added successful!");addModal.toggle()}}})}else{$("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none");$save_peer.removeAttr("disabled");$save_peer.html("Add")}}else{$("#add_peer_alert").html("Please enter 1 or more amount.").removeClass("d-none");$save_peer.removeAttr("disabled");$save_peer.html("Add")}};$save_peer.on("click",function(){let $bulk_add=$("#bulk_add");if($bulk_add.prop("checked")){bulk_add_peers()}else{let $public_key=$("#public_key");let $private_key=$("#private_key");let $allowed_ips=$("#allowed_ips");$allowed_ips.val(clean_ip($allowed_ips.val()));let $new_add_DNS=$("#new_add_DNS");$new_add_DNS.val(clean_ip($new_add_DNS.val()));let $new_add_endpoint_allowed_ip=$("#new_add_endpoint_allowed_ip");$new_add_endpoint_allowed_ip.val(clean_ip($new_add_endpoint_allowed_ip.val()));let $new_add_name=$("#new_add_name");let $new_add_MTU=$("#new_add_MTU");let $new_add_keep_alive=$("#new_add_keep_alive");let $enable_preshare_key=$("#enable_preshare_key");$(this).attr("disabled","disabled");$(this).html("Adding...");if($allowed_ips.val()!==""&&$public_key.val()!==""&&$new_add_DNS.val()!==""&&$new_add_endpoint_allowed_ip.val()!==""){let conf=$(this).attr("conf_id");let data_list=[$private_key,$allowed_ips,$new_add_name,$new_add_DNS,$new_add_endpoint_allowed_ip,$new_add_MTU,$new_add_keep_alive];data_list.forEach(ele=>ele.attr("disabled","disabled"));$.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:$new_add_DNS.val(),endpoint_allowed_ip:$new_add_endpoint_allowed_ip.val(),MTU:$new_add_MTU.val(),keep_alive:$new_add_keep_alive.val(),enable_preshared_key:$enable_preshare_key.prop("checked"),preshared_key:$enable_preshare_key.val()}),success:function(response){if(response!=="true"){$("#add_peer_alert").html(response).removeClass("d-none");data_list.forEach(ele=>ele.removeAttr("disabled"));$save_peer.removeAttr("disabled").html("Save")}else{load_data("");data_list.forEach(ele=>ele.removeAttr("disabled"));$("#add_peer_form").trigger("reset");$save_peer.removeAttr("disabled").html("Save");showToast("Add peer successful!");addModal.toggle()}}})}else{$("#add_peer_alert").html("Please fill in all required box.").removeClass("d-none");$(this).removeAttr("disabled");$(this).html("Add")}}});let qrcodeModal=new bootstrap.Modal(document.getElementById("qrcode_modal"),{keyboard:false});$body.on("click",".btn-qrcode-peer",function(){let src=$(this).attr("img_src");$.ajax({url:src,method:"GET"}).done(function(res){$("#qrcode_img").attr("src",res);qrcodeModal.toggle()})});let deleteModal=new bootstrap.Modal(document.getElementById("delete_modal"),{keyboard:false});$body.on("click",".btn-delete-peer",function(){let peer_id=$(this).attr("id");$("#delete_peer").attr("peer_id",peer_id);deleteModal.toggle()});$("#delete_peer").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Deleting...");let peer_id=$(this).attr("peer_id");let 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()).removeClass("d-none")}else{deleteModal.toggle();load_data($("#search_peer_textbox").val());$("#alertToast").toast("show");$("#alertToast .toast-body").html("Peer deleted!");$("#delete_peer").removeAttr("disabled").html("Delete")}}})});let settingModal=new bootstrap.Modal(document.getElementById("setting_modal"),{keyboard:false});$body.on("click",".btn-setting-peer",function(){startProgressBar();let 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(response.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 #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);$("#setting_modal #peer_preshared_key_textbox").val(response.preshared_key);settingModal.toggle();endProgressBar()}})});$("#setting_modal").on("hidden.bs.modal",function(event){$("#setting_peer_alert").addClass("d-none")});$("#peer_private_key_textbox").on("change",function(){let $save_peer_setting=$("#save_peer_setting");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.status).removeClass("d-none")}else{$("#setting_peer_alert").addClass("d-none")}})}});$("#save_peer_setting").on("click",function(){$(this).attr("disabled","disabled");$(this).html("Saving...");let $peer_DNS_textbox=$("#peer_DNS_textbox");let $peer_allowed_ip_textbox=$("#peer_allowed_ip_textbox");let $peer_endpoint_allowed_ips=$("#peer_endpoint_allowed_ips");let $peer_name_textbox=$("#peer_name_textbox");let $peer_private_key_textbox=$("#peer_private_key_textbox");let $peer_preshared_key_textbox=$("#peer_preshared_key_textbox");let $peer_mtu=$("#peer_mtu");let $peer_keep_alive=$("#peer_keep_alive");if($peer_DNS_textbox.val()!==""&&$peer_allowed_ip_textbox.val()!==""&&$peer_endpoint_allowed_ips.val()!==""){let peer_id=$(this).attr("peer_id");let conf_id=$(this).attr("conf_id");let data_list=[$peer_name_textbox,$peer_DNS_textbox,$peer_private_key_textbox,$peer_preshared_key_textbox,$peer_allowed_ip_textbox,$peer_endpoint_allowed_ips,$peer_mtu,$peer_keep_alive];data_list.forEach(ele=>ele.attr("disabled","disabled"));$.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(),endpoint_allowed_ip:$peer_endpoint_allowed_ips.val(),MTU:$peer_mtu.val(),keep_alive:$peer_keep_alive.val(),preshared_key:$peer_preshared_key_textbox.val()}),success:function(response){if(response.status==="failed"){$("#setting_peer_alert").html(response.msg).removeClass("d-none")}else{settingModal.toggle();load_data($("#search_peer_textbox").val());$("#alertToast").toast("show");$("#alertToast .toast-body").html("Peer Saved!")}$("#save_peer_setting").removeAttr("disabled").html("Save");data_list.forEach(ele=>ele.removeAttr("disabled"))}})}else{$("#setting_peer_alert").html("Please fill in all required box.").removeClass("d-none");$("#save_peer_setting").removeAttr("disabled").html("Save")}});$(".peer_private_key_textbox_switch").on("click",function(){let $peer_private_key_textbox=$("#peer_private_key_textbox");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)});let typingTimer;let doneTypingInterval=200;let $input=$("#search_peer_textbox");$input.on("keyup",function(){clearTimeout(typingTimer);typingTimer=setTimeout(doneTyping,doneTypingInterval)});$input.on("keydown",function(){clearTimeout(typingTimer)});function doneTyping(){load_data($input.val())}$body.on("change","#sort_by_dropdown",function(){$.ajax({method:"POST",data:JSON.stringify({sort:$("#sort_by_dropdown option:selected").val()}),headers:{"Content-Type":"application/json"},url:"/update_dashboard_sort",success:function(res){load_data($("#search_peer_textbox").val())}})});$body.on("mouseenter",".key",function(){let label=$(this).parent().siblings().children()[1];label.style.opacity="100"}).on("mouseout",".key",function(){let label=$(this).parent().siblings().children()[1];label.style.opacity="0";setTimeout(function(){label.innerHTML="CLICK TO COPY"},200)}).on("click",".key",function(){var label=$(this).parent().siblings().children()[1];copyToClipboard($(this));label.innerHTML="COPIED!"});function copyToClipboard(element){let $temp=$("");$body.append($temp);$temp.val($(element).text()).trigger("select");document.execCommand("copy");$temp.remove()}$body.on("click",".update_interval",function(){let prev=$(".interval-btn-group.active button");$(".interval-btn-group button").removeClass("active");let _new=$(this);_new.addClass("active");let interval=$(this).data("refresh-interval");$.ajax({method:"POST",data:"interval="+$(this).data("refresh-interval"),url:"/update_dashboard_refresh_interval",success:function(res){if(res==="true"){load_interval=interval;clearInterval(load_timeout);load_timeout=setInterval(function(){load_data($("#search_peer_textbox").val())},interval);showToast("Refresh Interval set to "+Math.round(interval/1e3)+" seconds")}else{$(".interval-btn-group button").removeClass("active");$('.interval-btn-group button[data-refresh-interval="'+load_interval+'"]').addClass("active");showToast("Refresh Interval set unsuccessful")}}})});$body.on("click",".refresh",function(){load_data($("#search_peer_textbox").val())});$body.on("click",".display_mode",function(){$(".display-btn-group button").removeClass("active");$(this).addClass("active");let display_mode=$(this).data("display-mode");$.ajax({method:"GET",url:"/switch_display_mode/"+$(this).data("display-mode"),success:function(res){if(res==="true"){if(display_mode==="list"){Array($(".peer_list").children()).forEach(function(child){$(child).removeClass().addClass("col-12")});showToast("Displaying as List")}else{Array($(".peer_list").children()).forEach(function(child){$(child).removeClass().addClass("col-sm-6 col-lg-4")});showToast("Displaying as Grids")}}}})});$("#bulk_add").on("change",function(){let hide=$(".non-bulk").find("input");let amount=$("#new_add_amount");if($(this).prop("checked")===true){for(let i=0;i. All Rights Reserved. + */ + +(function() { + function gf(init) { + var r = new Float64Array(16); + if (init) { + for (var i = 0; i < init.length; ++i) + r[i] = init[i]; + } + return r; + } + + function pack(o, n) { + var b, m = gf(), t = gf(); + for (var i = 0; i < 16; ++i) + t[i] = n[i]; + carry(t); + carry(t); + carry(t); + for (var j = 0; j < 2; ++j) { + m[0] = t[0] - 0xffed; + for (var i = 1; i < 15; ++i) { + m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); + m[i - 1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); + b = (m[15] >> 16) & 1; + m[14] &= 0xffff; + cswap(t, m, 1 - b); + } + for (var i = 0; i < 16; ++i) { + o[2 * i] = t[i] & 0xff; + o[2 * i + 1] = t[i] >> 8; + } + } + + function carry(o) { + var c; + for (var i = 0; i < 16; ++i) { + o[(i + 1) % 16] += (i < 15 ? 1 : 38) * Math.floor(o[i] / 65536); + o[i] &= 0xffff; + } + } + + function cswap(p, q, b) { + var t, c = ~(b - 1); + for (var i = 0; i < 16; ++i) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } + } + + function add(o, a, b) { + for (var i = 0; i < 16; ++i) + o[i] = (a[i] + b[i]) | 0; + } + + function subtract(o, a, b) { + for (var i = 0; i < 16; ++i) + o[i] = (a[i] - b[i]) | 0; + } + + function multmod(o, a, b) { + var t = new Float64Array(31); + for (var i = 0; i < 16; ++i) { + for (var j = 0; j < 16; ++j) + t[i + j] += a[i] * b[j]; + } + for (var i = 0; i < 15; ++i) + t[i] += 38 * t[i + 16]; + for (var i = 0; i < 16; ++i) + o[i] = t[i]; + carry(o); + carry(o); + } + + function invert(o, i) { + var c = gf(); + for (var a = 0; a < 16; ++a) + c[a] = i[a]; + for (var a = 253; a >= 0; --a) { + multmod(c, c, c); + if (a !== 2 && a !== 4) + multmod(c, c, i); + } + for (var a = 0; a < 16; ++a) + o[a] = c[a]; + } + + function clamp(z) { + z[31] = (z[31] & 127) | 64; + z[0] &= 248; + } + + function generatePublicKey(privateKey) { + var r, z = new Uint8Array(32); + var a = gf([1]), + b = gf([9]), + c = gf(), + d = gf([1]), + e = gf(), + f = gf(), + _121665 = gf([0xdb41, 1]), + _9 = gf([9]); + for (var i = 0; i < 32; ++i) + z[i] = privateKey[i]; + clamp(z); + for (var i = 254; i >= 0; --i) { + r = (z[i >>> 3] >>> (i & 7)) & 1; + cswap(a, b, r); + cswap(c, d, r); + add(e, a, c); + subtract(a, a, c); + add(c, b, d); + subtract(b, b, d); + multmod(d, e, e); + multmod(f, a, a); + multmod(a, c, a); + multmod(c, b, e); + add(e, a, c); + subtract(a, a, c); + multmod(b, a, a); + subtract(c, d, f); + multmod(a, c, _121665); + add(a, a, d); + multmod(c, c, a); + multmod(a, d, f); + multmod(d, b, _9); + multmod(b, e, e); + cswap(a, b, r); + cswap(c, d, r); + } + invert(c, c); + multmod(a, a, c); + pack(z, a); + return z; + } + + function generatePresharedKey() { + var privateKey = new Uint8Array(32); + window.crypto.getRandomValues(privateKey); + return privateKey; + } + + function generatePrivateKey() { + var privateKey = generatePresharedKey(); + clamp(privateKey); + return privateKey; + } + + function encodeBase64(dest, src) { + var input = Uint8Array.from([(src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63]); + for (var i = 0; i < 4; ++i) + dest[i] = input[i] + 65 + + (((25 - input[i]) >> 8) & 6) - + (((51 - input[i]) >> 8) & 75) - + (((61 - input[i]) >> 8) & 15) + + (((62 - input[i]) >> 8) & 3); + } + + function keyToBase64(key) { + var i, base64 = new Uint8Array(44); + for (i = 0; i < 32 / 3; ++i) + encodeBase64(base64.subarray(i * 4), key.subarray(i * 3)); + encodeBase64(base64.subarray(i * 4), Uint8Array.from([key[i * 3 + 0], key[i * 3 + 1], 0])); + base64[43] = 61; + return String.fromCharCode.apply(null, base64); + } + + window.wireguard = { + generateKeypair: function() { + var privateKey = generatePrivateKey(); + var publicKey = generatePublicKey(privateKey); + var presharedKey = generatePresharedKey(); + return { + publicKey: keyToBase64(publicKey), + privateKey: keyToBase64(privateKey), + presharedKey: keyToBase64(presharedKey) + }; + }, + generatePublicKey: function (privateKey){ + return keyToBase64(generatePublicKey(privateKey)) + } + }; +})(); diff --git a/src/static/js/wireguard.min.js b/src/static/js/wireguard.min.js new file mode 100644 index 0000000..a440aa6 --- /dev/null +++ b/src/static/js/wireguard.min.js @@ -0,0 +1 @@ +(function(){function gf(init){var r=new Float64Array(16);if(init){for(var i=0;i>16&1);m[i-1]&=65535}m[15]=t[15]-32767-(m[14]>>16&1);b=m[15]>>16&1;m[14]&=65535;cswap(t,m,1-b)}for(var i=0;i<16;++i){o[2*i]=t[i]&255;o[2*i+1]=t[i]>>8}}function carry(o){var c;for(var i=0;i<16;++i){o[(i+1)%16]+=(i<15?1:38)*Math.floor(o[i]/65536);o[i]&=65535}}function cswap(p,q,b){var t,c=~(b-1);for(var i=0;i<16;++i){t=c&(p[i]^q[i]);p[i]^=t;q[i]^=t}}function add(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]+b[i]|0}function subtract(o,a,b){for(var i=0;i<16;++i)o[i]=a[i]-b[i]|0}function multmod(o,a,b){var t=new Float64Array(31);for(var i=0;i<16;++i){for(var j=0;j<16;++j)t[i+j]+=a[i]*b[j]}for(var i=0;i<15;++i)t[i]+=38*t[i+16];for(var i=0;i<16;++i)o[i]=t[i];carry(o);carry(o)}function invert(o,i){var c=gf();for(var a=0;a<16;++a)c[a]=i[a];for(var a=253;a>=0;--a){multmod(c,c,c);if(a!==2&&a!==4)multmod(c,c,i)}for(var a=0;a<16;++a)o[a]=c[a]}function clamp(z){z[31]=z[31]&127|64;z[0]&=248}function generatePublicKey(privateKey){var r,z=new Uint8Array(32);var a=gf([1]),b=gf([9]),c=gf(),d=gf([1]),e=gf(),f=gf(),_121665=gf([56129,1]),_9=gf([9]);for(var i=0;i<32;++i)z[i]=privateKey[i];clamp(z);for(var i=254;i>=0;--i){r=z[i>>>3]>>>(i&7)&1;cswap(a,b,r);cswap(c,d,r);add(e,a,c);subtract(a,a,c);add(c,b,d);subtract(b,b,d);multmod(d,e,e);multmod(f,a,a);multmod(a,c,a);multmod(c,b,e);add(e,a,c);subtract(a,a,c);multmod(b,a,a);subtract(c,d,f);multmod(a,c,_121665);add(a,a,d);multmod(c,c,a);multmod(a,d,f);multmod(d,b,_9);multmod(b,e,e);cswap(a,b,r);cswap(c,d,r)}invert(c,c);multmod(a,a,c);pack(z,a);return z}function generatePresharedKey(){var privateKey=new Uint8Array(32);window.crypto.getRandomValues(privateKey);return privateKey}function generatePrivateKey(){var privateKey=generatePresharedKey();clamp(privateKey);return privateKey}function encodeBase64(dest,src){var input=Uint8Array.from([src[0]>>2&63,(src[0]<<4|src[1]>>4)&63,(src[1]<<2|src[2]>>6)&63,src[2]&63]);for(var i=0;i<4;++i)dest[i]=input[i]+65+(25-input[i]>>8&6)-(51-input[i]>>8&75)-(61-input[i]>>8&15)+(62-input[i]>>8&3)}function keyToBase64(key){var i,base64=new Uint8Array(44);for(i=0;i<32/3;++i)encodeBase64(base64.subarray(i*4),key.subarray(i*3));encodeBase64(base64.subarray(i*4),Uint8Array.from([key[i*3+0],key[i*3+1],0]));base64[43]=61;return String.fromCharCode.apply(null,base64)}window.wireguard={generateKeypair:function(){var privateKey=generatePrivateKey();var publicKey=generatePublicKey(privateKey);var presharedKey=generatePresharedKey();return{publicKey:keyToBase64(publicKey),privateKey:keyToBase64(privateKey),presharedKey:keyToBase64(presharedKey)}},generatePublicKey:function(privateKey){return keyToBase64(generatePublicKey(privateKey))}}})(); \ No newline at end of file diff --git a/src/templates/configuration.html b/src/templates/configuration.html index 83e3f6b..3ddbcac 100644 --- a/src/templates/configuration.html +++ b/src/templates/configuration.html @@ -100,9 +100,7 @@ - +
@@ -121,16 +119,29 @@ -
+
-
+
-
+
@@ -201,7 +212,7 @@
@@ -363,6 +374,7 @@ {% include "tools.html" %} {% include "footer.html" %} +