Added clients page filter by subnet range
This commit is contained in:
		
							parent
							
								
									53eaab0079
								
							
						
					
					
						commit
						2027b3fa5d
					
				|  | @ -18,6 +18,11 @@ function renderClientList(data) { | |||
|             allowedIpsHtml += `<small class="badge badge-secondary">${obj}</small> `; | ||||
|         }) | ||||
| 
 | ||||
|         let subnetRangesString = ""; | ||||
|         if (obj.Client.subnet_ranges && obj.Client.subnet_ranges.length > 0) { | ||||
|             subnetRangesString = obj.Client.subnet_ranges.join(',') | ||||
|         } | ||||
| 
 | ||||
|         // render client html content
 | ||||
|         let html = `<div class="col-sm-6 col-md-6 col-lg-4" id="client_${obj.Client.id}">
 | ||||
|                         <div class="info-box"> | ||||
|  | @ -59,6 +64,7 @@ function renderClientList(data) { | |||
|                                 <hr> | ||||
|                                 <span class="info-box-text"><i class="fas fa-user"></i> ${obj.Client.name}</span> | ||||
|                                 <span class="info-box-text" style="display: none"><i class="fas fa-key"></i> ${obj.Client.public_key}</span> | ||||
|                                 <span class="info-box-text" style="display: none"><i class="fas fa-subnetrange"></i>${subnetRangesString}</span> | ||||
|                                 <span class="info-box-text"><i class="fas fa-envelope"></i> ${obj.Client.email}</span> | ||||
|                                 <span class="info-box-text"><i class="fas fa-clock"></i> | ||||
|                                     ${prettyDateTime(obj.Client.created_at)}</span> | ||||
|  |  | |||
|  | @ -366,6 +366,10 @@ func GetClients(db store.IStore) echo.HandlerFunc { | |||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 		for i, clientData := range clientDataList { | ||||
| 			clientDataList[i] = util.FillClientSubnetRange(clientData) | ||||
| 		} | ||||
| 
 | ||||
| 		return c.JSON(http.StatusOK, clientDataList) | ||||
| 	} | ||||
| } | ||||
|  | @ -391,7 +395,7 @@ func GetClient(db store.IStore) echo.HandlerFunc { | |||
| 			return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "Client not found"}) | ||||
| 		} | ||||
| 
 | ||||
| 		return c.JSON(http.StatusOK, clientData) | ||||
| 		return c.JSON(http.StatusOK, util.FillClientSubnetRange(clientData)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ type Client struct { | |||
| 	PresharedKey    string    `json:"preshared_key"` | ||||
| 	Name            string    `json:"name"` | ||||
| 	Email           string    `json:"email"` | ||||
| 	SubnetRanges    []string  `json:"subnet_ranges,omitempty"` | ||||
| 	AllocatedIPs    []string  `json:"allocated_ips"` | ||||
| 	AllowedIPs      []string  `json:"allowed_ips"` | ||||
| 	ExtraAllowedIPs []string  `json:"extra_allowed_ips"` | ||||
|  |  | |||
|  | @ -58,11 +58,13 @@ | |||
|                 </div> | ||||
|                 <div class="form-group form-group-sm"> | ||||
|                     <select name="status-selector" id="status-selector" class="custom-select form-control-navbar" style="margin-left: 0.5em; height: 90%; font-size: 14px;"> | ||||
|                         <!-- SEE updateSearchList() in clients.html BEFORE EDITING --> | ||||
|                         <option value="All">All</option> | ||||
|                         <option value="Enabled">Enabled</option> | ||||
|                         <option value="Disabled">Disabled</option> | ||||
|                         <option value="Connected">Connected</option> | ||||
|                         <option value="Disconnected">Disconnected</option> | ||||
|                         <!-- SEE updateSearchList() in clients.html BEFORE EDITING --> | ||||
|                     </select> | ||||
|                 </div> | ||||
|             </form> | ||||
|  | @ -210,7 +212,7 @@ | |||
|                                 <input type="text" class="form-control" id="client_email" name="client_email"> | ||||
|                             </div> | ||||
|                             <div class="form-group"> | ||||
|                                 <label for="subnet_ranges" class="control-label">Subnet ranges</label> | ||||
|                                 <label for="subnet_ranges" class="control-label">Subnet range</label> | ||||
|                                 <select id="subnet_ranges" class="select2" | ||||
|                                     data-placeholder="Select a subnet range" style="width: 100%;"> | ||||
|                                 </select> | ||||
|  | @ -374,7 +376,6 @@ | |||
| 
 | ||||
|         $(document).ready(function () { | ||||
| 
 | ||||
| 
 | ||||
|             addGlobalStyle(` | ||||
|                 .toast-top-right-fix { | ||||
|                     top: 67px; | ||||
|  | @ -387,6 +388,8 @@ | |||
|             toastr.options.positionClass = 'toast-top-right-fix'; | ||||
| 
 | ||||
|             updateApplyConfigVisibility() | ||||
|             // from clients.html | ||||
|             updateSearchList() | ||||
| 
 | ||||
|         }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -279,6 +279,36 @@ Wireguard Clients | |||
|                 }); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         function updateSearchList() { | ||||
|             $.getJSON("{{.basePath}}/api/subnet-ranges", null, function(data) { | ||||
|                 $("#status-selector option").remove(); | ||||
|                 $("#status-selector").append( | ||||
|                     $("<option></option>") | ||||
|                         .text("All") | ||||
|                         .val("All"), | ||||
|                     $("<option></option>") | ||||
|                         .text("Enabled") | ||||
|                         .val("Enabled"), | ||||
|                     $("<option></option>") | ||||
|                         .text("Disabled") | ||||
|                         .val("Disabled"), | ||||
|                     $("<option></option>") | ||||
|                         .text("Connected") | ||||
|                         .val("Connected"), | ||||
|                     $("<option></option>") | ||||
|                         .text("Disconnected") | ||||
|                         .val("Disconnected") | ||||
|                 ); | ||||
|                 $.each(data, function(index, item) { | ||||
|                     $("#status-selector").append( | ||||
|                         $("<option></option>") | ||||
|                             .text(item) | ||||
|                             .val(item) | ||||
|                     ); | ||||
|                 }); | ||||
|             }); | ||||
| } | ||||
|     </script> | ||||
|     <script> | ||||
|         // load client list | ||||
|  | @ -368,7 +398,18 @@ Wireguard Clients | |||
|                     }); | ||||
|                     break; | ||||
|                 default: | ||||
|                     $('.col-lg-4').show(); | ||||
|                     $('.col-lg-4').hide(); | ||||
|                     const selectedSR = $("#status-selector").val() | ||||
|                     $(".fa-subnetrange").each(function () { | ||||
|                         const srs = $(this).parent().text().trim().split(',') | ||||
|                         for (const sr of srs) { | ||||
|                             if (sr === selectedSR) { | ||||
|                                 $(this).closest('.col-lg-4').show(); | ||||
|                                 break | ||||
|                             }                             | ||||
|                         } | ||||
|                     }) | ||||
|                     // $('.col-lg-4').show(); | ||||
|                     break; | ||||
|             } | ||||
|         }); | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| package util | ||||
| 
 | ||||
| var IPToSubnetRange = map[string]uint16{} | ||||
							
								
								
									
										38
									
								
								util/util.go
								
								
								
								
							
							
						
						
									
										38
									
								
								util/util.go
								
								
								
								
							|  | @ -410,6 +410,44 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip | |||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| // findSubnetRangeForIP to find first SR for IP, and cache the match
 | ||||
| func findSubnetRangeForIP(cidr string) (uint16, error) { | ||||
| 	ip, _, err := net.ParseCIDR(cidr) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	if srName, ok := IPToSubnetRange[ip.String()]; ok { | ||||
| 		return srName, nil | ||||
| 	} | ||||
| 
 | ||||
| 	for srIndex, sr := range SubnetRangesOrder { | ||||
| 		for _, srCIDR := range SubnetRanges[sr] { | ||||
| 			if srCIDR.Contains(ip) { | ||||
| 				IPToSubnetRange[ip.String()] = uint16(srIndex) | ||||
| 				return uint16(srIndex), nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("Subnet range not foud for this IP") | ||||
| } | ||||
| 
 | ||||
| // FillClientSubnetRange to fill subnet ranges client belongs to, does nothing if SRs are not found
 | ||||
| func FillClientSubnetRange(client model.ClientData) model.ClientData { | ||||
| 	cl := *client.Client | ||||
| 	for _, ip := range cl.AllocatedIPs { | ||||
| 		sr, err := findSubnetRangeForIP(ip) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		cl.SubnetRanges = append(cl.SubnetRanges, SubnetRangesOrder[sr]) | ||||
| 	} | ||||
| 	return model.ClientData{ | ||||
| 		Client: &cl, | ||||
| 		QRCode: client.QRCode, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ValidateAndFixSubnetRanges to check if subnet ranges are valid for the server configuration
 | ||||
| // Removes all non-valid CIDRs
 | ||||
| func ValidateAndFixSubnetRanges(db store.IStore) error { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue