Add bulk import for global firewall allow/block lists

Paste-in import: one CIDR/IP per line, optional comment after '#',
blank/comment-only lines ignored - matches the format used by common
public blocklist feeds (Spamhaus DROP, blocklist.de, etc.) so those can
mostly be pasted in directly. Whole batch gets one list_type (allow or
block). Reuses the existing single-entry validation, skips duplicates
(by list_type+CIDR, including within the same paste), caps at 5000 lines,
and reports imported/skipped/invalid counts plus per-line errors.

New route: POST /firewall-lists/entries/import (admin-only). UI: a
collapsible "Bulk import" section on the Global Firewall Lists page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-07-12 17:50:58 +02:00
co-authored by Claude Sonnet 5
parent eb1913d400
commit 77ba2b4799
3 changed files with 155 additions and 0 deletions
+55
View File
@@ -47,6 +47,28 @@ Global Firewall Lists
<button type="submit" class="btn btn-primary btn-sm mb-1">Add entry</button>
</form>
<hr>
<p><a data-toggle="collapse" href="#collapse_bulk_import" role="button" aria-expanded="false" aria-controls="collapse_bulk_import">Bulk import &#9660;</a></p>
<div class="collapse" id="collapse_bulk_import">
<div class="card card-body">
<form id="frm_iplist_import">
<div class="form-group">
<label for="_iplist_import_type">List type for this batch</label>
<select class="form-control form-control-sm" id="_iplist_import_type" style="width:10em">
<option value="block">block</option>
<option value="allow">allow</option>
</select>
</div>
<div class="form-group">
<label for="_iplist_import_text">Entries (one CIDR/IP per line)</label>
<textarea class="form-control" id="_iplist_import_text" rows="10"
placeholder="One CIDR or IP per line. Optional comment after '#'.&#10;Blank lines and lines starting with '#' are ignored.&#10;&#10;203.0.113.0/24&#10;198.51.100.5 # known scanner&#10;# this whole line is a comment"></textarea>
</div>
<button type="submit" class="btn btn-primary btn-sm">Import</button>
</form>
</div>
</div>
<hr>
<p class="text-muted mb-1">Ruleset preview:</p>
<pre id="_iplist_preview_text" style="max-height: 30vh; overflow:auto;"></pre>
@@ -135,6 +157,39 @@ Global Firewall Lists
});
});
$("#frm_iplist_import").on('submit', function (e) {
e.preventDefault();
const data = {
list_type: $("#_iplist_import_type").val(),
text: $("#_iplist_import_text").val()
};
$.ajax({
cache: false,
method: 'POST',
url: '{{.basePath}}/firewall-lists/entries/import',
dataType: 'json',
contentType: "application/json",
data: JSON.stringify(data),
success: function (result) {
let summary = "Imported " + result.imported + ", skipped " + result.skipped_duplicates + " duplicates";
if (result.invalid_count > 0) {
summary += ", " + result.invalid_count + " invalid lines";
console.warn("Bulk import invalid lines:", result.invalid_lines);
toastr.warning(summary);
} else {
toastr.success(summary);
}
$("#_iplist_import_text").val("");
loadIPList();
refreshGlobalPreview();
},
error: function (jqXHR) {
const responseJson = jQuery.parseJSON(jqXHR.responseText);
toastr.error(responseJson['message'] || "Import failed");
}
});
});
$("#_iplist_tbody").on('click', '.btn-delete-iplist', function () {
const id = $(this).data('id');
if (!confirm("Delete this entry?")) return;