Added clients page filter by subnet range

This commit is contained in:
0xCA 2023-11-06 02:53:55 +05:00
parent 53eaab0079
commit 2027b3fa5d
7 changed files with 103 additions and 7 deletions

View file

@ -18,6 +18,11 @@ function renderClientList(data) {
allowedIpsHtml += `<small class="badge badge-secondary">${obj}</small>&nbsp;`; allowedIpsHtml += `<small class="badge badge-secondary">${obj}</small>&nbsp;`;
}) })
let subnetRangesString = "";
if (obj.Client.subnet_ranges && obj.Client.subnet_ranges.length > 0) {
subnetRangesString = obj.Client.subnet_ranges.join(',')
}
// render client html content // render client html content
let html = `<div class="col-sm-6 col-md-6 col-lg-4" id="client_${obj.Client.id}"> let html = `<div class="col-sm-6 col-md-6 col-lg-4" id="client_${obj.Client.id}">
<div class="info-box"> <div class="info-box">
@ -59,6 +64,7 @@ function renderClientList(data) {
<hr> <hr>
<span class="info-box-text"><i class="fas fa-user"></i> ${obj.Client.name}</span> <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-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-envelope"></i> ${obj.Client.email}</span>
<span class="info-box-text"><i class="fas fa-clock"></i> <span class="info-box-text"><i class="fas fa-clock"></i>
${prettyDateTime(obj.Client.created_at)}</span> ${prettyDateTime(obj.Client.created_at)}</span>

View file

@ -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) 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.StatusNotFound, jsonHTTPResponse{false, "Client not found"})
} }
return c.JSON(http.StatusOK, clientData) return c.JSON(http.StatusOK, util.FillClientSubnetRange(clientData))
} }
} }

View file

@ -12,6 +12,7 @@ type Client struct {
PresharedKey string `json:"preshared_key"` PresharedKey string `json:"preshared_key"`
Name string `json:"name"` Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
SubnetRanges []string `json:"subnet_ranges,omitempty"`
AllocatedIPs []string `json:"allocated_ips"` AllocatedIPs []string `json:"allocated_ips"`
AllowedIPs []string `json:"allowed_ips"` AllowedIPs []string `json:"allowed_ips"`
ExtraAllowedIPs []string `json:"extra_allowed_ips"` ExtraAllowedIPs []string `json:"extra_allowed_ips"`

View file

@ -58,11 +58,13 @@
</div> </div>
<div class="form-group form-group-sm"> <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;"> <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="All">All</option>
<option value="Enabled">Enabled</option> <option value="Enabled">Enabled</option>
<option value="Disabled">Disabled</option> <option value="Disabled">Disabled</option>
<option value="Connected">Connected</option> <option value="Connected">Connected</option>
<option value="Disconnected">Disconnected</option> <option value="Disconnected">Disconnected</option>
<!-- SEE updateSearchList() in clients.html BEFORE EDITING -->
</select> </select>
</div> </div>
</form> </form>
@ -210,7 +212,7 @@
<input type="text" class="form-control" id="client_email" name="client_email"> <input type="text" class="form-control" id="client_email" name="client_email">
</div> </div>
<div class="form-group"> <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" <select id="subnet_ranges" class="select2"
data-placeholder="Select a subnet range" style="width: 100%;"> data-placeholder="Select a subnet range" style="width: 100%;">
</select> </select>
@ -374,7 +376,6 @@
$(document).ready(function () { $(document).ready(function () {
addGlobalStyle(` addGlobalStyle(`
.toast-top-right-fix { .toast-top-right-fix {
top: 67px; top: 67px;
@ -387,6 +388,8 @@
toastr.options.positionClass = 'toast-top-right-fix'; toastr.options.positionClass = 'toast-top-right-fix';
updateApplyConfigVisibility() updateApplyConfigVisibility()
// from clients.html
updateSearchList()
}); });

View file

@ -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>
<script> <script>
// load client list // load client list
@ -368,7 +398,18 @@ Wireguard Clients
}); });
break; break;
default: 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; break;
} }
}); });

3
util/cache.go Normal file
View file

@ -0,0 +1,3 @@
package util
var IPToSubnetRange = map[string]uint16{}

View file

@ -410,6 +410,44 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip
return true, nil 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 // ValidateAndFixSubnetRanges to check if subnet ranges are valid for the server configuration
// Removes all non-valid CIDRs // Removes all non-valid CIDRs
func ValidateAndFixSubnetRanges(db store.IStore) error { func ValidateAndFixSubnetRanges(db store.IStore) error {