mirror of
https://github.com/ngoduykhanh/wireguard-ui
synced 2024-06-10 18:02:26 +02:00
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> `;
|
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
|
// 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>
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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
3
util/cache.go
Normal file
|
@ -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
|
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 {
|
||||||
|
|
Loading…
Reference in a new issue