feat: add localhost web UI for scans, blocklist, and firewall management
This commit is contained in:
1 parent
a9dc560f80
commit
4ef6892916
19 files changed
+1934
-117
No files matched your search
@@ -0,0 +1,77 @@
|
||||
// Shared helpers for the Intrusion Detection web UI.
|
||||
|
||||
async function api(path, options = {}) {
|
||||
const opts = { headers: {}, ...options };
|
||||
if (opts.body && typeof opts.body !== "string") {
|
||||
opts.headers["Content-Type"] = "application/json";
|
||||
opts.body = JSON.stringify(opts.body);
|
||||
}
|
||||
const res = await fetch(path, opts);
|
||||
let data = null;
|
||||
try {
|
||||
data = await res.json();
|
||||
} catch (e) {
|
||||
/* non-JSON */
|
||||
}
|
||||
if (!res.ok) {
|
||||
const msg = (data && (data.error || data.message)) || `HTTP ${res.status}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s ?? "").replace(
|
||||
/[&<>"']/g,
|
||||
(c) =>
|
||||
({
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
})[c],
|
||||
);
|
||||
}
|
||||
|
||||
function toast(message, type = "info") {
|
||||
const box = document.getElementById("toasts");
|
||||
if (!box) return;
|
||||
const node = document.createElement("div");
|
||||
node.className = `toast toast-${type}`;
|
||||
node.textContent = message;
|
||||
box.appendChild(node);
|
||||
setTimeout(() => node.remove(), 4000);
|
||||
}
|
||||
|
||||
function fmtTime(s) {
|
||||
if (!s) return "—";
|
||||
const d = new Date(s);
|
||||
return isNaN(d) ? s : d.toLocaleString();
|
||||
}
|
||||
|
||||
function badge(state) {
|
||||
const node = document.createElement("span");
|
||||
node.className = `badge ${state}`;
|
||||
node.textContent = state;
|
||||
return node;
|
||||
}
|
||||
|
||||
function el(tag, attrs = {}, ...children) {
|
||||
const node = document.createElement(tag);
|
||||
for (const [k, v] of Object.entries(attrs || {})) {
|
||||
if (k === "class") node.className = v;
|
||||
else if (k === "text") node.textContent = v;
|
||||
else if (k === "html") node.innerHTML = v;
|
||||
else if (k.startsWith("on")) node.addEventListener(k.slice(2), v);
|
||||
else node.setAttribute(k, v);
|
||||
}
|
||||
for (const c of children) {
|
||||
node.append(c == null ? "" : c);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
async function startScan(kind, params) {
|
||||
return api(`/api/scan/${kind}`, { method: "POST", body: params });
|
||||
}
|
||||
Reference in new issue
Block a user