From f9bb6cfe7dfda26f2f9200b57393a5c2d2e3805c Mon Sep 17 00:00:00 2001 From: Khanh Ngo <k@ndk.name> Date: Tue, 2 Jun 2020 11:08:39 +0700 Subject: [PATCH] Edit client --- custom/js/helper.js | 4 +-- handler/routes.go | 63 ++++++++++++++++++++++++++++++++-- main.go | 1 + templates/base.html | 2 +- templates/clients.html | 78 ++++++++++++++++++++++++++++++++++++++++++ util/util.go | 14 ++++---- 6 files changed, 150 insertions(+), 12 deletions(-) diff --git a/custom/js/helper.js b/custom/js/helper.js index 9591026..42bc17a 100644 --- a/custom/js/helper.js +++ b/custom/js/helper.js @@ -9,13 +9,13 @@ function renderClientList(data) { // render client allocated ip addresses let allocatedIpsHtml = ""; $.each(obj.Client.allocated_ips, function(index, obj) { - allocatedIpsHtml += `<small class="badge badge-secondary">${obj}</small>`; + allocatedIpsHtml += `<small class="badge badge-secondary">${obj}</small> `; }) // render client allowed ip addresses let allowedIpsHtml = ""; $.each(obj.Client.allowed_ips, function(index, obj) { - allowedIpsHtml += `<small class="badge badge-secondary">${obj}</small>`; + allowedIpsHtml += `<small class="badge badge-secondary">${obj}</small> `; }) // render client html content diff --git a/handler/routes.go b/handler/routes.go index 39b3ceb..5164fd6 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -145,7 +145,7 @@ func NewClient() echo.HandlerFunc { } // validate the input Allocation IPs - allocatedIPs, err := util.GetAllocatedIPs() + allocatedIPs, err := util.GetAllocatedIPs("") check, err := util.ValidateIPAllocation(serverInterface.Addresses, allocatedIPs, client.AllocatedIPs) if !check { return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, fmt.Sprintf("%s", err)}) @@ -188,6 +188,63 @@ func NewClient() echo.HandlerFunc { } } +// UpdateClient handler to update client information +func UpdateClient() echo.HandlerFunc { + return func(c echo.Context) error { + // access validation + validSession(c) + + _client := new(model.Client) + c.Bind(_client) + + db, err := util.DBConn() + if err != nil { + log.Error("Cannot initialize database: ", err) + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot access database"}) + } + + // validate client existence + client := model.Client{} + if err := db.Read("clients", _client.ID, &client); err != nil { + return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) + } + + // read server information + serverInterface := model.ServerInterface{} + if err := db.Read("server", "interfaces", &serverInterface); err != nil { + log.Error("Cannot fetch server interface config from database: ", err) + return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, fmt.Sprintf("Cannot fetch server config: %s", err)}) + } + + // validate the input Allocation IPs + allocatedIPs, err := util.GetAllocatedIPs(client.ID) + check, err := util.ValidateIPAllocation(serverInterface.Addresses, allocatedIPs, _client.AllocatedIPs) + if !check { + return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, fmt.Sprintf("%s", err)}) + } + + // validate the input AllowedIPs + if util.ValidateAllowedIPs(_client.AllowedIPs) == false { + log.Warnf("Invalid Allowed IPs input from user: %v", _client.AllowedIPs) + return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Allowed IPs must be in CIDR format"}) + } + + // map new data + client.Name = _client.Name + client.Email = _client.Email + client.Enabled = _client.Enabled + client.AllocatedIPs = _client.AllocatedIPs + client.AllowedIPs = _client.AllowedIPs + client.UpdatedAt = time.Now().UTC() + + // write to the database + db.Write("clients", client.ID, &client) + log.Infof("Updated client information successfully => %v", client) + + return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated client successfully"}) + } +} + // SetClientStatus handler to enable / disable a client func SetClientStatus() echo.HandlerFunc { return func(c echo.Context) error { @@ -212,7 +269,7 @@ func SetClientStatus() echo.HandlerFunc { client := model.Client{} if err := db.Read("clients", clientID, &client); err != nil { - log.Error("Cannot fetch server interface config from database: ", err) + log.Error("Cannot get client from database: ", err) } client.Enabled = status @@ -451,7 +508,7 @@ func SuggestIPAllocation() echo.HandlerFunc { // we take the first available ip address from // each server's network addresses. suggestedIPs := make([]string, 0) - allocatedIPs, err := util.GetAllocatedIPs() + allocatedIPs, err := util.GetAllocatedIPs("") if err != nil { log.Error("Cannot suggest ip allocation. Failed to get list of allocated ip addresses: ", err) return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot suggest ip allocation: failed to get list of allocated ip addresses"}) diff --git a/main.go b/main.go index 95ce032..b289c99 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ func main() { app.POST("/login", handler.Login()) app.GET("/logout", handler.Logout()) app.POST("/new-client", handler.NewClient()) + app.POST("/update-client", handler.UpdateClient()) app.POST("/client/set-status", handler.SetClientStatus()) app.POST("/remove-client", handler.RemoveClient()) app.GET("/download", handler.DownloadClient()) diff --git a/templates/base.html b/templates/base.html index 681bb45..0e04f31 100644 --- a/templates/base.html +++ b/templates/base.html @@ -377,7 +377,7 @@ }, client_email: { required: "Please enter an email address", - email: "Please enter a vaild email address" + email: "Please enter a valid email address" }, }, errorElement: 'span', diff --git a/templates/clients.html b/templates/clients.html index 33fd92f..689d5d2 100644 --- a/templates/clients.html +++ b/templates/clients.html @@ -41,6 +41,7 @@ Wireguard Clients </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"> @@ -276,6 +277,7 @@ Wireguard Clients 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); @@ -298,5 +300,81 @@ Wireguard Clients }); }); }); + + // 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 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, "enabled": enabled}; + + $.ajax({ + cache: false, + method: 'POST', + url: '/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']); + } + }); + } + + // Edit client form validation + $(document).ready(function () { + $.validator.setDefaults({ + submitHandler: function () { + submitEditClient(); + } + }); + $("#frm_edit_client").validate({ + rules: { + client_name: { + required: true, + }, + client_email: { + required: true, + email: true, + }, + }, + messages: { + client_name: { + required: "Please enter a name" + }, + client_email: { + required: "Please enter an email address", + email: "Please enter a valid email address" + }, + }, + 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}} \ No newline at end of file diff --git a/util/util.go b/util/util.go index 384886f..d98aaec 100644 --- a/util/util.go +++ b/util/util.go @@ -173,7 +173,7 @@ func GetIPFromCIDR(cidr string) (string, error) { } // GetAllocatedIPs to get all ip addresses allocated to clients and server -func GetAllocatedIPs() ([]string, error) { +func GetAllocatedIPs(ignoreClientID string) ([]string, error) { allocatedIPs := make([]string, 0) // initialize database directory @@ -211,12 +211,14 @@ func GetAllocatedIPs() ([]string, error) { return nil, err } - for _, cidr := range client.AllocatedIPs { - ip, err := GetIPFromCIDR(cidr) - if err != nil { - return nil, err + if client.ID != ignoreClientID { + for _, cidr := range client.AllocatedIPs { + ip, err := GetIPFromCIDR(cidr) + if err != nil { + return nil, err + } + allocatedIPs = append(allocatedIPs, ip) } - allocatedIPs = append(allocatedIPs, ip) } }