move IP/Network lists to the data provider

this is a backward incompatible change, all previous file based IP/network
lists will not work anymore

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2023-02-09 09:33:33 +01:00
parent 2412a0a369
commit 1b1745b7f7
103 changed files with 4958 additions and 1284 deletions

View File

@@ -101,7 +101,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<b>Role</b>
</div>
<div class="card-body">
<h6 class="card-title mb-4">Setting a role limit the administrator to only manage users with the same role. Role administrators cannot have the following permissions: "manage_admins", "manage_roles", "manage_event_rules", "manage_apikeys", "manage_system"</h6>
<h6 class="card-title mb-4">Setting a role limit the administrator to only manage users with the same role. Role administrators cannot have the following permissions: "manage_admins", "manage_roles", "manage_event_rules", "manage_apikeys", "manage_system", "manage_ip_lists"</h6>
<div class="form-group row">
<label for="idRole" class="col-sm-2 col-form-label">Role</label>
<div class="col-sm-10">

View File

@@ -73,7 +73,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<i class="fas fa-users"></i>
<span>{{.UsersTitle}}</span></a>
</li>
{{ end }}
{{ if .LoggedAdmin.HasPermission "manage_groups"}}
<li class="nav-item {{if eq .CurrentURL .GroupsURL}}active{{end}}">
<a class="nav-link" href="{{.GroupsURL}}">
<i class="fas fa-user-friends"></i>
<span>{{.GroupsTitle}}</span></a>
</li>
{{end}}
{{ if .LoggedAdmin.HasPermission "view_users"}}
<li class="nav-item {{if eq .CurrentURL .FoldersURL}}active{{end}}">
<a class="nav-link" href="{{.FoldersURL}}">
<i class="fas fa-folder"></i>
@@ -81,11 +91,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</li>
{{end}}
{{ if .LoggedAdmin.HasPermission "manage_groups"}}
<li class="nav-item {{if eq .CurrentURL .GroupsURL}}active{{end}}">
<a class="nav-link" href="{{.GroupsURL}}">
<i class="fas fa-user-friends"></i>
<span>{{.GroupsTitle}}</span></a>
{{ if .LoggedAdmin.HasPermission "view_conns"}}
<li class="nav-item {{if eq .CurrentURL .ConnectionsURL}}active{{end}}">
<a class="nav-link" href="{{.ConnectionsURL}}">
<i class="fas fa-exchange-alt"></i>
<span>{{.ConnectionsTitle}}</span></a>
</li>
{{end}}
@@ -105,27 +115,23 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</li>
{{end}}
{{ if .LoggedAdmin.HasPermission "view_conns"}}
<li class="nav-item {{if eq .CurrentURL .ConnectionsURL}}active{{end}}">
<a class="nav-link" href="{{.ConnectionsURL}}">
<i class="fas fa-exchange-alt"></i>
<span>{{.ConnectionsTitle}}</span></a>
</li>
{{end}}
{{ if and .HasDefender (.LoggedAdmin.HasPermission "view_defender")}}
<li class="nav-item {{if eq .CurrentURL .DefenderURL}}active{{end}}">
<a class="nav-link" href="{{.DefenderURL}}">
{{ if or (.LoggedAdmin.HasPermission "manage_ip_lists") (and .HasDefender (.LoggedAdmin.HasPermission "view_defender"))}}
<li class="nav-item {{if .IsIPManagerPage}}active{{end}}">
<a class="nav-link {{if not .IsIPManagerPage}}collapsed{{end}}" href="#" data-toggle="collapse" data-target="#collapseIPManager"
aria-expanded="true" aria-controls="collapseIPManager">
<i class="fas fa-shield-alt"></i>
<span>{{.DefenderTitle}}</span></a>
</li>
{{end}}
{{ if .LoggedAdmin.HasPermission "manage_roles"}}
<li class="nav-item {{if eq .CurrentURL .RolesURL}}active{{end}}">
<a class="nav-link" href="{{.RolesURL}}">
<i class="fas fa-user-lock"></i>
<span>{{.RolesTitle}}</span></a>
<span>IP Manager</span>
</a>
<div id="collapseIPManager" class="collapse {{if .IsIPManagerPage}}show{{end}}" aria-labelledby="headingIPManager" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
{{ if .LoggedAdmin.HasPermission "manage_ip_lists"}}
<a class="collapse-item {{if eq .CurrentURL .IPListsURL}}active{{end}}" href="{{.IPListsURL}}">{{.IPListsTitle}}</a>
{{end}}
{{ if and .HasDefender (.LoggedAdmin.HasPermission "view_defender")}}
<a class="collapse-item {{if eq .CurrentURL .DefenderURL}}active{{end}}" href="{{.DefenderURL}}">{{.DefenderTitle}}</a>
{{end}}
</div>
</div>
</li>
{{end}}
@@ -137,6 +143,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</li>
{{end}}
{{ if .LoggedAdmin.HasPermission "manage_roles"}}
<li class="nav-item {{if eq .CurrentURL .RolesURL}}active{{end}}">
<a class="nav-link" href="{{.RolesURL}}">
<i class="fas fa-user-lock"></i>
<span>{{.RolesTitle}}</span></a>
</li>
{{end}}
{{ if and .HasSearcher (.LoggedAdmin.HasPermission "view_events")}}
<li class="nav-item {{if eq .CurrentURL .EventsURL}}active{{end}}">
<a class="nav-link" href="{{.EventsURL}}">

View File

@@ -31,7 +31,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">View and manage blocklist</h6>
<h6 class="m-0 font-weight-bold text-primary">View and manage auto blocklist</h6>
</div>
<div class="card-body">
<div class="table-responsive">
@@ -63,7 +63,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">Do you want to remoce the selected blocklist entry?</div>
<div class="modal-body">Do you want to remoce the selected entry?</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">
Cancel
@@ -89,10 +89,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script type="text/javascript">
function deleteAction() {
var table = $('#dataTable').DataTable();
let table = $('#dataTable').DataTable();
table.button('delete:name').enable(false);
var id = table.row({ selected: true }).data()["id"];
var path = '{{.DefenderHostsURL}}' + "/" + fixedEncodeURIComponent(id);
let id = table.row({ selected: true }).data()["id"];
let path = '{{.DefenderHostsURL}}' + "/" + fixedEncodeURIComponent(id);
$('#deleteModal').modal('hide');
$.ajax({
url: path,
@@ -104,9 +104,9 @@ function deleteAction() {
window.location.href = '{{.DefenderURL}}';
},
error: function ($xhr, textStatus, errorThrown) {
var txt = "Unable to delete the selected entry";
let txt = "Unable to delete the selected entry";
if ($xhr) {
var json = $xhr.responseJSON;
let json = $xhr.responseJSON;
if (json) {
if (json.message){
txt += ": " + json.message;
@@ -144,15 +144,15 @@ function deleteAction() {
enabled: false
};
var table = $('#dataTable').DataTable({
let table = $('#dataTable').DataTable({
"ajax": {
"url": "{{.DefenderHostsURL}}",
"dataSrc": "",
"error": function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide();
var txt = "Failed to get defender's list";
let txt = "Failed to get auto blocklist";
if ($xhr) {
var json = $xhr.responseJSON;
let json = $xhr.responseJSON;
if (json) {
if (json.message){
txt += ": " + json.message;
@@ -218,7 +218,7 @@ function deleteAction() {
{{if .LoggedAdmin.HasPermission "manage_defender"}}
table.on('select deselect', function () {
var selectedRows = table.rows({ selected: true }).count();
let selectedRows = table.rows({ selected: true }).count();
table.button('delete:name').enable(selectedRows == 1);
});
{{end}}

View File

@@ -23,7 +23,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
{{define "additionalnavitems"}}
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="editorDropdown" role="button"
<a class="nav-link dropdown-toggle" href="#" id="infoDropdown" role="button"
data-toggle="modal" data-target="#infoModal">
<i class="fas fa-info fa-fw"></i>
</a>

View File

@@ -157,7 +157,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
let dateFn = $.fn.dataTable.render.datetime();
let isFsDataTableInitialized = false;
let isProviderDataTableInitialized = false;
let pageSize = 20;
const pageSize = 20;
const paginationData = new Map();
function fileSizeIEC(a,b,c,d,e){
@@ -231,7 +231,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
paginationData.set("prevClicked",false);
paginationData.set("nextClicked",false);
let exportURL = getSearchURL(true);
var ts = new Date().getTime().toString();
let ts = new Date().getTime().toString();
window.open(`${exportURL}&_=${ts}`);
}
@@ -338,9 +338,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"dataSrc": handleResponseData,
"error": function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide();
var txt = "Failed to get provider events";
let txt = "Failed to get provider events";
if ($xhr) {
var json = $xhr.responseJSON;
let json = $xhr.responseJSON;
if (json) {
if (json.message){
txt += ": " + json.message;
@@ -423,7 +423,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"dataSrc": handleResponseData,
"error": function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide();
var txt = "Failed to get filesystem events";
let txt = "Failed to get filesystem events";
if ($xhr) {
let json = $xhr.responseJSON;
if (json) {

View File

@@ -0,0 +1,104 @@
<!--
Copyright (C) 2019-2023 Nicola Murino
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
{{template "base" .}}
{{define "title"}}{{.Title}}{{end}}
{{define "extra_css"}}
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
{{end}}
{{define "page_body"}}
<!-- Page Heading -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">{{.Title}}</h6>
</div>
<div class="card-body">
{{if .Error}}
<div class="card mb-4 border-left-warning">
<div class="card-body text-form-error">{{.Error}}</div>
</div>
{{end}}
<form id="iplist_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">
<div class="form-group row">
<label for="idIPOrNet" class="col-sm-2 col-form-label">IP/Network</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idIPOrNet" name="ipornet" placeholder=""
value="{{.Entry.IPOrNet}}" maxlength="50" autocomplete="nope" aria-describedby="ipOrNetHelpBlock" required {{if eq .Mode 2}}readonly{{end}}>
{{if ne .Mode 2}}
<small id="ipOrNetHelpBlock" class="form-text text-muted">
IP address or network in CIDR format, example: "192.168.1.1 or 10.8.0.100/32 or 2001:db8:1234::/48"
</small>
{{end}}
</div>
</div>
<div class="form-group row">
<label for="idType" class="col-sm-2 col-form-label">Type</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idType" name="type" placeholder=""
value="{{.Entry.Type.AsString}}" maxlength="50" readonly>
</div>
</div>
{{if eq .Entry.Type 2}}
<div class="form-group row">
<label for="idMode" class="col-sm-2 col-form-label">Mode</label>
<div class="col-sm-10">
<select class="form-control selectpicker" id="idMode" name="mode">
<option value="2" {{if eq .Entry.Mode 2 }}selected{{end}}>Deny</option>
<option value="1" {{if eq .Entry.Mode 1 }}selected{{end}}>Allow</option>
</select>
</div>
</div>
{{end}}
<div class="form-group row">
<label for="idProtocols" class="col-sm-2 col-form-label">Protocols</label>
<div class="col-sm-10">
<select class="form-control selectpicker" id="idProtocols" name="protocols" multiple title="Any">
<option value="1" {{if .Entry.HasProtocol "SSH" }}selected{{end}}>SSH</option>
<option value="2" {{if .Entry.HasProtocol "FTP" }}selected{{end}}>FTP</option>
<option value="4" {{if .Entry.HasProtocol "DAV" }}selected{{end}}>DAV</option>
<option value="8" {{if .Entry.HasProtocol "HTTP" }}selected{{end}}>HTTP</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="idDescription" class="col-sm-2 col-form-label">Note</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="idDescription" name="description" placeholder=""
value="{{.Entry.Description}}" maxlength="512" aria-describedby="descriptionHelpBlock">
<small id="descriptionHelpBlock" class="form-text text-muted">
Optional note
</small>
</div>
</div>
<input type="hidden" name="_form_token" value="{{.CSRFToken}}">
<div class="col-sm-12 text-right px-0">
<button type="submit" class="btn btn-primary mt-3 ml-3 px-5" name="form_action" value="submit">Submit</button>
</div>
</form>
</div>
</div>
{{end}}
{{define "extra_js"}}
<script src="{{.StaticURL}}/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
{{end}}

View File

@@ -0,0 +1,508 @@
<!--
Copyright (C) 2019-2023 Nicola Murino
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
{{template "base" .}}
{{define "title"}}{{.Title}}{{end}}
{{define "extra_css"}}
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
{{end}}
{{define "page_body"}}
<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
<div id="errorTxt" class="card-body text-form-error"></div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">View and manage IP Lists</h6>
</div>
<div class="card-body">
{{if not .HasDefender}}
<div id="defender-info" class="card mb-3 border-left-info" style="display: none;">
<div class="card-body">Defender disabled in your configuration</div>
</div>
{{end}}
{{if not .IsAllowListEnabled}}
<div id="allowlist-info" class="card mb-3 border-left-info" style="display: none;">
<div class="card-body">Allowlist disabled in your configuration</div>
</div>
{{end}}
{{if not .RateLimitersStatus}}
<div id="ratelimited-info" class="card mb-3 border-left-info" style="display: none;">
<div class="card-body">Ratelimiters disabled in your configuration</div>
</div>
{{end}}
<div class="form-row">
<div class="form-group col-md-3">
<select class="form-control selectpicker" id="idListType" name="list_type" onchange="onListChanged(this.value)">
<option value="2">Defender</option>
<option value="1">Allow list</option>
<option value="3">Rate limiters safe list</option>
</select>
</div>
<div class="form-group col-md-5">
</div>
<div class="form-group col-md-4">
<div class="input-group">
<input type="text" class="form-control bg-light border-0" id="idIp" name="ip" placeholder="IP/Network or initial part" aria-describedby="search-button">
<div class="input-group-append">
<button id="search-button" class="btn btn-primary" type="button" onclick="onSearchClicked()">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover nowrap" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>IP/Network</th>
<th>Protocols</th>
<th>Mode</th>
<th>Note</th>
</tr>
</thead>
</table>
</div>
<div id="paginationContainer" class="m-4 d-none">
<nav aria-label="Pagination">
<ul class="pagination justify-content-end">
<li id="pageItemPrev" class="page-item disabled"><a id="pagePrevious" class="page-link" href="#" onclick="prevClicked()">Previous</a></li>
<li id="pageItemNext" class="page-item disabled"><a id="pageNext" class="page-link" href="#" onclick="nextClicked()">Next</a></li>
</ul>
</nav>
</div>
</div>
</div>
{{end}}
{{define "dialog"}}
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">
Confirmation required
</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">Do you want to remoce the selected entry?</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">
Cancel
</button>
<a class="btn btn-warning" href="#" onclick="deleteAction()">
Delete
</a>
</div>
</div>
</div>
</div>
{{end}}
{{define "extra_js"}}
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
<script src="{{.StaticURL}}/vendor/datatables/ellipsis.js"></script>
<script src="{{.StaticURL}}/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
<script type="text/javascript">
const prefListTypeName = 'sftpgo_pref_{{.LoggedAdmin.Username}}_iplist_type';
const prefListFilter = 'sftpgo_pref_{{.LoggedAdmin.Username}}_iplist_search_filter';
const listType = getListType();
const listFilter = getSearchFilter();
if (listType === '1' || listType === '3'){
$('#idListType').val(listType);
} else {
$('#idListType').val('2');
}
if (listFilter){
$('#idIp').val(listFilter);
} else {
$('#idIp').val('');
}
const pageSize = 15;
const paginationData = new Map();
function saveListType(val) {
localStorage.setItem(prefListTypeName, val);
}
function getListType() {
return localStorage.getItem(prefListTypeName);
}
function saveSearchFilter() {
let val = $("#idIp").val();
if (val){
localStorage.setItem(prefListFilter, val);
} else {
localStorage.removeItem(prefListFilter);
}
}
function getSearchFilter() {
return localStorage.getItem(prefListFilter);
}
function resetPagination() {
$('#pageItemPrev').addClass("disabled");
$('#pageItemNext').addClass("disabled");
$('#paginationContainer').addClass("d-none");
paginationData.delete("firstIpOrNet");
paginationData.delete("lastIpOrNet");
paginationData.set("prevClicked",false);
paginationData.set("nextClicked",false);
}
function prevClicked(){
paginationData.set("prevClicked",true);
paginationData.set("nextClicked",false);
doSearch();
}
function nextClicked(){
paginationData.set("prevClicked",false);
paginationData.set("nextClicked",true);
doSearch();
}
function handleResponseData(data) {
let length = data.length;
let isNext = paginationData.get("nextClicked");
let isPrev = paginationData.get("prevClicked");
if (length > pageSize) {
data.pop();
length--;
if (isPrev || isNext){
$('#pageItemPrev').removeClass("disabled");
}
$('#pageItemNext').removeClass("disabled");
} else {
if (isPrev){
$('#pageItemPrev').addClass("disabled");
$('#pageItemNext').removeClass("disabled");
} else if (isNext){
$('#pageItemPrev').removeClass("disabled");
$('#pageItemNext').addClass("disabled");
} else {
$('#pageItemNext').addClass("disabled");
}
}
if (isPrev){
data = data.reverse();
}
if (length > 0){
paginationData.set("firstIpOrNet",data[0].ipornet);
paginationData.set("lastIpOrNet",data[length-1].ipornet);
$('#paginationContainer').removeClass("d-none");
} else {
resetPagination();
}
return data;
}
function getSearchURL(){
let listType = fixedEncodeURIComponent($("#idListType").val());
let filter = encodeURIComponent($("#idIp").val());
let limit = pageSize + 1;
let from = "";
let order = "ASC"
if (paginationData.get("nextClicked") && paginationData.has("lastIpOrNet")){
from = encodeURIComponent(paginationData.get("lastIpOrNet"));
}
if (paginationData.get("prevClicked") && paginationData.has("firstIpOrNet")){
from = encodeURIComponent(paginationData.get("firstIpOrNet"));
order = "DESC";
}
return "{{.IPListsURL}}"+`/${listType}?filter=${filter}&from=${from}&limit=${limit}&order=${order}`;
}
function deleteAction() {
let table = $('#dataTable').DataTable();
table.button('delete:name').enable(false);
let selectedRow = table.row({ selected: true }).data();
let path = '{{.IPListURL}}' + "/" + fixedEncodeURIComponent(selectedRow["type"])+"/"+ fixedEncodeURIComponent(selectedRow["ipornet"]);
$('#deleteModal').modal('hide');
$.ajax({
url: path,
type: 'DELETE',
dataType: 'json',
headers: {'X-CSRF-TOKEN' : '{{.CSRFToken}}'},
timeout: 15000,
success: function (result) {
window.location.href = '{{.IPListsURL}}';
},
error: function ($xhr, textStatus, errorThrown) {
let txt = "Unable to delete the selected entry";
if ($xhr) {
let json = $xhr.responseJSON;
if (json) {
if (json.message){
txt += ": " + json.message;
} else {
txt += ": " + json.error;
}
}
}
$('#errorTxt').text(txt);
$('#errorMsg').show();
setTimeout(function () {
$('#errorMsg').hide();
}, 5000);
}
});
}
function setTableColumnVisibility(val){
let column = $('#dataTable').DataTable().column(2);
switch (val){
case '2':
column.visible(true);
break;
default:
column.visible(false);
}
}
function updateListTypeInfo(val) {
let info1 = $('#allowlist-info');
let info2 = $('#defender-info');
let info3 = $('#ratelimited-info');
if (info1){
info1.hide();
}
if (info2){
info2.hide();
}
if (info3){
info3.hide();
}
switch (val){
case '1':
if (info1){
info1.show();
}
break;
case '2':
if (info2){
info2.show();
}
break;
case '3':
if (info3){
info3.show();
}
break;
}
}
function onListChanged(val){
saveListType(val);
updateListTypeInfo(val);
setTableColumnVisibility(val);
let table = $('#dataTable').DataTable();
table.clear().draw();
table.ajax.url(getSearchURL()).load();
}
function onSearchClicked(){
resetPagination();
doSearch();
saveSearchFilter();
}
function doSearch(){
let table = $('#dataTable').DataTable();
table.clear().draw();
table.ajax.url(getSearchURL()).load();
}
$(document).ready(function () {
$.fn.dataTable.ext.buttons.add = {
text: '<i class="fas fa-plus"></i>',
name: 'add',
titleAttr: "Add",
action: function (e, dt, node, config) {
window.location.href = '{{.IPListURL}}'+"/"+fixedEncodeURIComponent($("#idListType").val());
}
};
$.fn.dataTable.ext.buttons.edit = {
text: '<i class="fas fa-pen"></i>',
name: 'edit',
titleAttr: "Edit",
action: function (e, dt, node, config) {
let selectedRow = table.row({ selected: true }).data();
let path = '{{.IPListURL}}' + "/" + fixedEncodeURIComponent(selectedRow["type"])+"/"+ fixedEncodeURIComponent(selectedRow["ipornet"]);
window.location.href = path;
},
enabled: false
};
$.fn.dataTable.ext.buttons.delete = {
text: '<i class="fas fa-trash"></i>',
name: 'delete',
titleAttr: "Delete",
action: function (e, dt, node, config) {
$('#deleteModal').modal('show');
},
enabled: false
};
let table = $('#dataTable').DataTable({
"ajax": {
"url": getSearchURL(),
"dataSrc": handleResponseData,
"error": function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide();
let txt = "Failed to get IP list";
if ($xhr) {
let json = $xhr.responseJSON;
if (json) {
if (json.message){
txt += ": " + json.message;
} else {
txt += ": " + json.error;
}
}
}
$('#errorTxt').text(txt);
$('#errorMsg').show();
setTimeout(function () {
$('#errorMsg').hide();
}, 10000);
}
},
"deferRender": true,
"processing": true,
"columns": [
{ "data": "ipornet" },
{
"data": "protocols",
"render": function (data, type, row) {
if (type === 'display') {
if (data == 0){
return "Any";
}
const protocols = [];
if ((data & 1) != 0){
protocols.push('SSH');
}
if ((data & 2) != 0){
protocols.push('FTP');
}
if ((data & 4) != 0){
protocols.push('DAV');
}
if ((data & 8) != 0){
protocols.push('HTTP');
}
return protocols.join(', ');
}
return data;
}
},
{
"data": "mode",
"render": function (data, type, row) {
if (type === 'display') {
if (data == 1){
return "Allow";
}
return "Deny";
}
return data;
}
},
{
"data": "description",
"render": function (data, type, row) {
if (type === 'display') {
let ellipsisFn = $.fn.dataTable.render.ellipsis(70, true);
return ellipsisFn(data,type);
}
return data;
}
}
],
"select": {
"style": "single",
"blurable": true
},
"buttons": [],
"lengthChange": false,
"columnDefs": [],
"responsive": true,
"searching": false,
"paging": false,
"info": false,
"ordering": false,
"language": {
"loadingRecords": "",
"emptyTable": "No entries found"
},
"initComplete": function (settings, json) {
table.button().add(0, 'delete');
table.button().add(0, 'edit');
table.button().add(0, 'add');
table.buttons().container().appendTo('.col-md-6:eq(0)', table.table().container());
}
});
new $.fn.dataTable.FixedHeader(table);
$.fn.dataTable.ext.errMode = 'none';
table.on('select deselect', function () {
let selectedRows = table.rows({ selected: true }).count();
table.button('delete:name').enable(selectedRows == 1);
table.button('edit:name').enable(selectedRows == 1);
});
resetPagination();
let listType = $('#idListType').val();
setTableColumnVisibility(listType);
updateListTypeInfo(listType);
});
</script>
{{end}}

View File

@@ -17,10 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
{{define "title"}}{{.Title}}{{end}}
{{define "extra_css"}}
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
{{end}}
{{define "page_body"}}
<!-- Page Heading -->
<div class="card shadow mb-4">

View File

@@ -150,8 +150,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
name: 'edit',
titleAttr: "Edit",
action: function (e, dt, node, config) {
var roleName = table.row({ selected: true }).data()[0];
var path = '{{.RoleURL}}' + "/" + fixedEncodeURIComponent(roleName);
let roleName = table.row({ selected: true }).data()[0];
let path = '{{.RoleURL}}' + "/" + fixedEncodeURIComponent(roleName);
window.location.href = path;
},
enabled: false

View File

@@ -100,6 +100,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</div>
</div>
<div class="card mb-4 {{ if .Status.AllowList.IsActive}}border-left-success{{else}}border-left-info{{end}}">
<div class="card-body">
<h6 class="card-title font-weight-bold">Allow list</h6>
<p class="card-text">
Status: {{ if .Status.AllowList.IsActive}}"Enabled"{{else}}"Disabled"{{end}}
</p>
</div>
</div>
<div class="card mb-4 {{ if .Status.Defender.IsActive}}border-left-success{{else}}border-left-info{{end}}">
<div class="card-body">
<h6 class="card-title font-weight-bold">Defender</h6>
@@ -109,6 +118,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
</div>
</div>
<div class="card mb-4 {{ if .Status.RateLimiters.IsActive}}border-left-success{{else}}border-left-info{{end}}">
<div class="card-body">
<h6 class="card-title font-weight-bold">Rate limiters</h6>
<p class="card-text">
Status: {{ if .Status.RateLimiters.IsActive}}"Enabled"{{else}}"Disabled"{{end}}
{{if .Status.RateLimiters.IsActive}}
<br>
Protocols: {{.Status.RateLimiters.GetProtocolsAsString}}
{{end}}
</p>
</div>
</div>
<div class="card mb-4 {{ if .Status.MFA.IsActive}}border-left-success{{else}}border-left-info{{end}}">
<div class="card-body">
<h6 class="card-title font-weight-bold">Multi-factor authentication</h6>

View File

@@ -32,7 +32,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
{{end}}
{{define "additionalnavitems"}}
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="editorDropdown" role="button"
<a class="nav-link dropdown-toggle" href="#" id="infoDropdown" role="button"
data-toggle="modal" data-target="#infoModal">
<i class="fas fa-info fa-fw"></i>
</a>