diff --git a/Dockerfile b/Dockerfile index 3d73d38..88fa7e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,9 @@ RUN mkdir -p assets/plugins && \ /build/node_modules/jquery-tags-input/ \ assets/plugins/ +# Move custom assets +RUN cp -r /build/custom/ assets/ + # Get go modules and build tool RUN go mod download && \ go get github.com/GeertJohan/go.rice/rice diff --git a/custom/js/helper.js b/custom/js/helper.js new file mode 100644 index 0000000..42bc17a --- /dev/null +++ b/custom/js/helper.js @@ -0,0 +1,60 @@ +function renderClientList(data) { + $.each(data, function(index, obj) { + // render client status css tag style + let clientStatusHtml = '>' + if (obj.Client.enabled) { + clientStatusHtml = `style="visibility: hidden;">` + } + + // render client allocated ip addresses + let allocatedIpsHtml = ""; + $.each(obj.Client.allocated_ips, function(index, obj) { + allocatedIpsHtml += `${obj} `; + }) + + // render client allowed ip addresses + let allowedIpsHtml = ""; + $.each(obj.Client.allowed_ips, function(index, obj) { + allowedIpsHtml += `${obj} `; + }) + + // render client html content + let html = `
+
+
+
+ +
+
+ + + + +
+
+ ${obj.Client.name} + ${obj.Client.email} + + ${obj.Client.created_at} + + ${obj.Client.updated_at} + IP Allocation` + + allocatedIpsHtml + + `Allowed IPs` + + allowedIpsHtml + +`
+
+
` + + // add the client html elements to the list + $('#client-list').append(html); + }); +} diff --git a/handler/routes.go b/handler/routes.go index 156fecc..5164fd6 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -92,6 +92,37 @@ func WireGuardClients() echo.HandlerFunc { } } +// GetClients handler return a list of Wireguard client data +func GetClients() echo.HandlerFunc { + return func(c echo.Context) error { + // access validation + validSession(c) + + clientDataList, err := util.GetClients(true) + if err != nil { + return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, fmt.Sprintf("Cannot get client list: %v", err)}) + } + + return c.JSON(http.StatusOK, clientDataList) + } +} + +// GetClient handler return a of Wireguard client data +func GetClient() echo.HandlerFunc { + return func(c echo.Context) error { + // access validation + validSession(c) + + clientID := c.Param("id") + clientData, err := util.GetClientByID(clientID, true) + if err != nil { + return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) + } + + return c.JSON(http.StatusOK, clientData) + } +} + // NewClient handler func NewClient() echo.HandlerFunc { return func(c echo.Context) error { @@ -114,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)}) @@ -157,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 { @@ -181,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 @@ -200,15 +288,16 @@ func DownloadClient() echo.HandlerFunc { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Missing clientid parameter"}) } - client, err := util.GetClientByID(clientID) + clientData, err := util.GetClientByID(clientID, false) if err != nil { log.Errorf("Cannot generate client id %s config file for downloading: %v", clientID, err) return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) } + // build config server, _ := util.GetServer() globalSettings, _ := util.GetGlobalSettings() - config := util.BuildClientConfig(client, server, globalSettings) + config := util.BuildClientConfig(*clientData.Client, server, globalSettings) // create io reader from string reader := strings.NewReader(config) @@ -419,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 0022951..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()) @@ -57,6 +58,8 @@ func main() { app.POST("wg-server/keypair", handler.WireGuardServerKeyPair()) app.GET("/global-settings", handler.GlobalSettings()) app.POST("/global-settings", handler.GlobalSettingSubmit()) + app.GET("/api/clients", handler.GetClients()) + app.GET("/api/client/:id", handler.GetClient()) app.GET("/api/machine-ips", handler.MachineIPAddresses()) app.GET("/api/suggest-client-ips", handler.SuggestIPAllocation()) app.GET("/api/apply-wg-config", handler.ApplyServerConfig(tmplBox)) diff --git a/prepare_assets.sh b/prepare_assets.sh index 801da8c..31dd1bb 100755 --- a/prepare_assets.sh +++ b/prepare_assets.sh @@ -11,6 +11,9 @@ mkdir -p "${DIR}/assets/dist/js" "${DIR}/assets/dist/css" && \ cp -r "${DIR}/node_modules/admin-lte/dist/js/adminlte.min.js" "${DIR}/assets/dist/js/adminlte.min.js" && \ cp -r "${DIR}/node_modules/admin-lte/dist/css/adminlte.min.css" "${DIR}/assets/dist/css/adminlte.min.css" +# Copy helper js +cp -r "${DIR}/custom" "${DIR}/assets" + # Copy plugins mkdir -p "${DIR}/assets/plugins" && \ cp -r "${DIR}/node_modules/admin-lte/plugins/jquery" \ diff --git a/templates/base.html b/templates/base.html index 542aca7..0e04f31 100644 --- a/templates/base.html +++ b/templates/base.html @@ -56,16 +56,17 @@ - -