mirror of
https://github.com/ngoduykhanh/wireguard-ui.git
synced 2025-04-21 20:12:33 +03:00

When downloading QR code, the filename will be Client name, instead of generic. Ability to left click on QR code to download it.
600 lines
24 KiB
HTML
600 lines
24 KiB
HTML
{{define "title"}}
|
|
Wireguard Clients
|
|
{{end}}
|
|
|
|
{{define "top_css"}}
|
|
<style>
|
|
.paused-client {
|
|
transition: transform .2s;
|
|
cursor: pointer;
|
|
}
|
|
i[class^="paused-client"]:hover { transform: scale(1.5); }
|
|
</style>
|
|
{{end}}
|
|
|
|
{{define "username"}}
|
|
{{ .username }}
|
|
{{end}}
|
|
|
|
{{define "page_title"}}
|
|
Wireguard Clients
|
|
{{end}}
|
|
|
|
{{define "page_content"}}
|
|
<section class="content">
|
|
<div class="container-fluid">
|
|
<!-- <h5 class="mt-4 mb-2">Wireguard Clients</h5> -->
|
|
<div class="row" id="client-list">
|
|
</div>
|
|
<!-- /.row -->
|
|
</div>
|
|
</section>
|
|
|
|
<div class="modal fade" id="modal_email_client">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Email Configuration</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form name="frm_email_client" id="frm_email_client">
|
|
<div class="modal-body">
|
|
<input type="hidden" id="e_client_id" name="e_client_id">
|
|
<div class="form-group">
|
|
<label for="e_client_email" class="control-label">Email address</label>
|
|
<input type="text" class="form-control" id="e_client_email" name="e_client_email">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer justify-content-between">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-success">Send</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- /.modal-content -->
|
|
</div>
|
|
<!-- /.modal-dialog -->
|
|
</div>
|
|
<!-- /.modal -->
|
|
|
|
<div class="modal fade" id="modal_qr_client">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">QR Code</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" id="qr_client_id" name="qr_client_id">
|
|
<a href="" download="" id="qr_code_a">
|
|
<img id="qr_code" class="w-100" style="image-rendering: pixelated;" src="" alt="QR code" />
|
|
</a>
|
|
<div class="form-group">
|
|
<div class="icheck-primary d-inline">
|
|
<input type="checkbox" id="qr_include_fwmark" onchange="regenerateQRCode()">
|
|
<label for="qr_include_fwmark">
|
|
Include FwMark
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- /.modal-content -->
|
|
</div>
|
|
<!-- /.modal-dialog -->
|
|
</div>
|
|
<!-- /.modal -->
|
|
|
|
<div class="modal fade" id="modal_edit_client">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Edit Client</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form name="frm_edit_client" id="frm_edit_client">
|
|
<div class="modal-body">
|
|
<input type="hidden" id="_client_id" name="_client_id">
|
|
<div class="form-group">
|
|
<label for="_client_name" class="control-label">Name</label>
|
|
<input type="text" class="form-control" id="_client_name" name="_client_name">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="_client_email" class="control-label">Email</label>
|
|
<input type="text" class="form-control" id="_client_email" name="client_email">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="_client_allocated_ips" class="control-label">IP Allocation</label>
|
|
<input type="text" data-role="tagsinput" class="form-control" id="_client_allocated_ips">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="_client_allowed_ips" class="control-label">Allowed IPs</label>
|
|
<input type="text" data-role="tagsinput" class="form-control" id="_client_allowed_ips">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="_client_extra_allowed_ips" class="control-label">Extra Allowed IPs</label>
|
|
<input type="text" data-role="tagsinput" class="form-control"
|
|
id="_client_extra_allowed_ips">
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="icheck-primary d-inline">
|
|
<input type="checkbox" id="_use_server_dns">
|
|
<label for="_use_server_dns">
|
|
Use server DNS
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="icheck-primary d-inline">
|
|
<input type="checkbox" id="_enabled">
|
|
<label for="_enabled">
|
|
Enable this client
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer justify-content-between">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-success">Save</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- /.modal-content -->
|
|
</div>
|
|
<!-- /.modal-dialog -->
|
|
</div>
|
|
<!-- /.modal -->
|
|
|
|
<div class="modal fade" id="modal_pause_client">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content bg-warning">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Disable</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
</div>
|
|
<div class="modal-footer justify-content-between">
|
|
<button type="button" class="btn btn-outline-dark" data-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-outline-dark" id="pause_client_confirm">Apply</button>
|
|
</div>
|
|
</div>
|
|
<!-- /.modal-content -->
|
|
</div>
|
|
<!-- /.modal-dialog -->
|
|
</div>
|
|
<!-- /.modal -->
|
|
|
|
<div class="modal fade" id="modal_remove_client">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content bg-danger">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Remove</h4>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
</div>
|
|
<div class="modal-footer justify-content-between">
|
|
<button type="button" class="btn btn-outline-dark" data-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-outline-dark" id="remove_client_confirm">Apply</button>
|
|
</div>
|
|
</div>
|
|
<!-- /.modal-content -->
|
|
</div>
|
|
<!-- /.modal-dialog -->
|
|
</div>
|
|
<!-- /.modal -->
|
|
{{end}}
|
|
|
|
{{define "bottom_js"}}
|
|
<script>
|
|
function populateClientList() {
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'GET',
|
|
url: '{{.basePath}}/api/clients',
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
renderClientList(data);
|
|
},
|
|
error: function (jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
}
|
|
|
|
function setClientStatus(clientID, status) {
|
|
const data = {"id": clientID, "status": status};
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'POST',
|
|
url: '{{.basePath}}/client/set-status',
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
data: JSON.stringify(data),
|
|
success: function (data) {
|
|
console.log("Set client " + clientID + " status to " + status);
|
|
},
|
|
error: function (jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
}
|
|
|
|
function resumeClient(clientID) {
|
|
setClientStatus(clientID, true);
|
|
const divElement = document.getElementById("paused_" + clientID);
|
|
divElement.style.visibility = "hidden";
|
|
}
|
|
|
|
function pauseClient(clientID) {
|
|
setClientStatus(clientID, false);
|
|
const divElement = document.getElementById("paused_" + clientID);
|
|
divElement.style.visibility = "visible";
|
|
}
|
|
</script>
|
|
<script>
|
|
// load client list
|
|
$(document).ready(function () {
|
|
populateClientList();
|
|
})
|
|
|
|
// modal_pause_client modal event
|
|
$("#modal_pause_client").on('show.bs.modal', function (event) {
|
|
const button = $(event.relatedTarget);
|
|
const client_id = button.data('clientid');
|
|
const client_name = button.data('clientname');
|
|
const modal = $(this);
|
|
modal.find('.modal-body').text("You are about to disable client " + client_name);
|
|
modal.find('#pause_client_confirm').val(client_id);
|
|
})
|
|
|
|
// pause_client_confirm button event
|
|
$(document).ready(function () {
|
|
$("#pause_client_confirm").click(function () {
|
|
const client_id = $(this).val();
|
|
pauseClient(client_id);
|
|
$("#modal_pause_client").modal('hide');
|
|
});
|
|
});
|
|
|
|
// modal_remove_client modal event
|
|
$("#modal_remove_client").on('show.bs.modal', function (event) {
|
|
const button = $(event.relatedTarget);
|
|
const client_id = button.data('clientid');
|
|
const client_name = button.data('clientname');
|
|
const modal = $(this);
|
|
modal.find('.modal-body').text("You are about to remove client " + client_name);
|
|
modal.find('#remove_client_confirm').val(client_id);
|
|
})
|
|
|
|
// remove_client_confirm button event
|
|
$(document).ready(function () {
|
|
$("#remove_client_confirm").click(function () {
|
|
const client_id = $(this).val();
|
|
const data = {"id": client_id};
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'POST',
|
|
url: '{{.basePath}}/remove-client',
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
data: JSON.stringify(data),
|
|
success: function(data) {
|
|
$("#modal_remove_client").modal('hide');
|
|
toastr.success('Removed client successfully');
|
|
const divElement = document.getElementById('client_' + client_id);
|
|
divElement.style.display = "none";
|
|
},
|
|
error: function(jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// Edit client modal event
|
|
$(document).ready(function () {
|
|
$("#modal_edit_client").on('show.bs.modal', function (event) {
|
|
let modal = $(this);
|
|
const button = $(event.relatedTarget);
|
|
const client_id = button.data('clientid');
|
|
|
|
// IP Allocation tag input
|
|
modal.find("#_client_allocated_ips").tagsInput({
|
|
'width': '100%',
|
|
'height': '75%',
|
|
'interactive': true,
|
|
'defaultText': 'Add More',
|
|
'removeWithBackspace': true,
|
|
'minChars': 0,
|
|
'placeholderColor': '#666666'
|
|
});
|
|
|
|
// AllowedIPs tag input
|
|
modal.find("#_client_allowed_ips").tagsInput({
|
|
'width': '100%',
|
|
'height': '75%',
|
|
'interactive': true,
|
|
'defaultText': 'Add More',
|
|
'removeWithBackspace': true,
|
|
'minChars': 0,
|
|
'placeholderColor': '#666666'
|
|
});
|
|
|
|
modal.find("#_client_extra_allowed_ips").tagsInput({
|
|
'width': '100%',
|
|
'height': '75%',
|
|
'interactive': true,
|
|
'defaultText': 'Add More',
|
|
'removeWithBackspace' : true,
|
|
'minChars': 0,
|
|
'placeholderColor': '#666666'
|
|
})
|
|
|
|
// update client modal data
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'GET',
|
|
url: '{{.basePath}}/api/client/' + client_id,
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
success: function (resp) {
|
|
const client = resp.Client;
|
|
|
|
modal.find(".modal-title").text("Edit Client " + client.name);
|
|
modal.find("#_client_id").val(client.id);
|
|
modal.find("#_client_name").val(client.name);
|
|
modal.find("#_client_email").val(client.email);
|
|
|
|
modal.find("#_client_allocated_ips").importTags('');
|
|
client.allocated_ips.forEach(function (obj) {
|
|
modal.find("#_client_allocated_ips").addTag(obj);
|
|
});
|
|
|
|
modal.find("#_client_allowed_ips").importTags('');
|
|
client.allowed_ips.forEach(function (obj) {
|
|
modal.find("#_client_allowed_ips").addTag(obj);
|
|
});
|
|
|
|
modal.find("#_client_extra_allowed_ips").importTags('');
|
|
client.extra_allowed_ips.forEach(function (obj) {
|
|
modal.find("#_client_extra_allowed_ips").addTag(obj);
|
|
});
|
|
|
|
modal.find("#_use_server_dns").prop("checked", client.use_server_dns);
|
|
modal.find("#_enabled").prop("checked", client.enabled);
|
|
},
|
|
error: function (jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// regenerateQRCode function for regenerating QR Code adding/removing some parts of configuration because of compatibility issues with some clients
|
|
function regenerateQRCode() {
|
|
const client_id = $("#qr_client_id").val();
|
|
const QRCodeImg = $("#qr_code");
|
|
const QRCodeA = $("#qr_code_a");
|
|
let include_fwmark = false;
|
|
if ($("#qr_include_fwmark").is(':checked')){
|
|
include_fwmark = true;
|
|
}
|
|
QRCodeImg.hide();
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'GET',
|
|
url: '{{.basePath}}/api/client/' + client_id,
|
|
data: {
|
|
qrCodeIncludeFwMark: include_fwmark
|
|
},
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
success: function (resp) {
|
|
const client = resp.Client;
|
|
|
|
$(".modal-title").text("Scan QR Code for " + client.name + " profile");
|
|
QRCodeImg.attr('src', resp.QRCode).show();
|
|
QRCodeA.attr('download', resp.Client.name);
|
|
QRCodeA.attr('href', resp.QRCode).show();
|
|
|
|
},
|
|
error: function (jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
}
|
|
|
|
// submitEmailClient function for sending an email with the configuration to the client
|
|
function submitEmailClient() {
|
|
const client_id = $("#e_client_id").val();
|
|
const email = $("#e_client_email").val();
|
|
const data = {"id": client_id, "email": email};
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'POST',
|
|
url: '{{.basePath}}/email-client',
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
data: JSON.stringify(data),
|
|
success: function(resp) {
|
|
$("#modal_email_client").modal('hide');
|
|
toastr.success('Sent email to client successfully');
|
|
// Refresh the home page (clients page) after sending email successfully
|
|
location.reload();
|
|
},
|
|
error: function(jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
}
|
|
|
|
// submitEditClient function for updating an existing client
|
|
function submitEditClient() {
|
|
const client_id = $("#_client_id").val();
|
|
const name = $("#_client_name").val();
|
|
const email = $("#_client_email").val();
|
|
const allocated_ips = $("#_client_allocated_ips").val().split(",");
|
|
const allowed_ips = $("#_client_allowed_ips").val().split(",");
|
|
let use_server_dns = false;
|
|
let extra_allowed_ips = [];
|
|
|
|
if( $("#_client_extra_allowed_ips").val() !== "" ) {
|
|
extra_allowed_ips = $("#_client_extra_allowed_ips").val().split(",");
|
|
}
|
|
|
|
if ($("#_use_server_dns").is(':checked')){
|
|
use_server_dns = true;
|
|
}
|
|
|
|
let enabled = false;
|
|
|
|
if ($("#_enabled").is(':checked')){
|
|
enabled = true;
|
|
}
|
|
|
|
const data = {"id": client_id, "name": name, "email": email, "allocated_ips": allocated_ips,
|
|
"allowed_ips": allowed_ips, "extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enabled": enabled};
|
|
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'POST',
|
|
url: '{{.basePath}}/update-client',
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
data: JSON.stringify(data),
|
|
success: function(resp) {
|
|
$("#modal_edit_client").modal('hide');
|
|
toastr.success('Updated client successfully');
|
|
// Refresh the home page (clients page) after updating successfully
|
|
location.reload();
|
|
},
|
|
error: function(jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
}
|
|
|
|
// submitHandler
|
|
function submitHandler(form) {
|
|
const formId = $(form).attr('id');
|
|
if (formId === "frm_edit_client") {
|
|
submitEditClient();
|
|
} else if (formId === "frm_email_client") {
|
|
submitEmailClient();
|
|
}
|
|
}
|
|
|
|
$("#modal_email_client").on('show.bs.modal', function (event) {
|
|
let modal = $(this);
|
|
const button = $(event.relatedTarget);
|
|
const client_id = button.data('clientid');
|
|
$.ajax({
|
|
cache: false,
|
|
method: 'GET',
|
|
url: '{{.basePath}}/api/client/' + client_id,
|
|
dataType: 'json',
|
|
contentType: "application/json",
|
|
success: function (resp) {
|
|
const client = resp.Client;
|
|
|
|
modal.find(".modal-title").text("Send config to client " + client.name);
|
|
modal.find("#e_client_id").val(client.id);
|
|
modal.find("#e_client_email").val(client.email);
|
|
},
|
|
error: function (jqXHR, exception) {
|
|
const responseJson = jQuery.parseJSON(jqXHR.responseText);
|
|
toastr.error(responseJson['message']);
|
|
}
|
|
});
|
|
});
|
|
|
|
$("#modal_qr_client").on('show.bs.modal', function (event) {
|
|
let modal = $(this);
|
|
const button = $(event.relatedTarget);
|
|
const client_id = button.data('clientid');
|
|
|
|
modal.find("#qr_client_id").val(client_id);
|
|
regenerateQRCode();
|
|
});
|
|
|
|
$(document).ready(function () {
|
|
$.validator.setDefaults({
|
|
submitHandler: function (form) {
|
|
submitHandler(form);
|
|
}
|
|
});
|
|
// Edit client form validation
|
|
$("#frm_edit_client").validate({
|
|
rules: {
|
|
client_name: {
|
|
required: true,
|
|
},
|
|
},
|
|
messages: {
|
|
client_name: {
|
|
required: "Please enter a name"
|
|
},
|
|
},
|
|
errorElement: 'span',
|
|
errorPlacement: function (error, element) {
|
|
error.addClass('invalid-feedback');
|
|
element.closest('.form-group').append(error);
|
|
},
|
|
highlight: function (element, errorClass, validClass) {
|
|
$(element).addClass('is-invalid');
|
|
},
|
|
unhighlight: function (element, errorClass, validClass) {
|
|
$(element).removeClass('is-invalid');
|
|
}
|
|
});
|
|
// Email client form validation
|
|
$("#frm_email_client").validate({
|
|
rules: {
|
|
e_client_email: {
|
|
required: true,
|
|
email: true,
|
|
},
|
|
},
|
|
messages: {
|
|
e_client_email: {
|
|
required: "Please enter an email"
|
|
},
|
|
},
|
|
errorElement: 'span',
|
|
errorPlacement: function (error, element) {
|
|
error.addClass('invalid-feedback');
|
|
element.closest('.form-group').append(error);
|
|
},
|
|
highlight: function (element, errorClass, validClass) {
|
|
$(element).addClass('is-invalid');
|
|
},
|
|
unhighlight: function (element, errorClass, validClass) {
|
|
$(element).removeClass('is-invalid');
|
|
}
|
|
});
|
|
//
|
|
});
|
|
</script>
|
|
{{end}}
|