- Added schema definition and migration logic in app/db/schema.py. - Created tables for log sources, requests, IP stats, scans, blocklist, whitelist, and firewall rules. - Introduced functions to apply migrations and ensure database integrity. feat: Enhance scan functionality with database integration - Added _sync_blocklist_to_db function to synchronize blocklist with SQLite. - Updated run_scan function to handle database connections and scan records. - Implemented error handling for database operations during scans. feat: Introduce log analysis page and API endpoints - Created analysis.html template for displaying log analysis results. - Added routes for fetching top IPs, IP request timelines, and cross-source IPs. - Integrated analysis data into the dashboard and status endpoints. fix: Ensure whitelists are synchronized with the database - Implemented sync_whitelists_to_db function to persist in-memory whitelists. - Updated constants.py to define the path for the SQLite database. refactor: Modularize analysis helpers for better maintainability - Created _analysis_helpers function to encapsulate SQLite query logic. - Updated routes.py to utilize new analysis helper functions for API responses.
110 lines
3.1 KiB
HTML
110 lines
3.1 KiB
HTML
{% extends "base.html" %} {% block title %}Dashboard — Intrusion Detection{%
|
|
endblock %} {% block content %}
|
|
<h1>Dashboard</h1>
|
|
<p class="muted">
|
|
Localhost-only control panel for the intrusion detection scanner.
|
|
</p>
|
|
|
|
<div class="cards" id="status-cards"></div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-head">
|
|
<h2>Latest scans</h2>
|
|
<a class="btn ghost" href="/scan">Run a scan →</a>
|
|
</div>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Job</th>
|
|
<th>Kind</th>
|
|
<th>State</th>
|
|
<th>Started</th>
|
|
<th>Finished</th>
|
|
<th class="num">Blocked</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="latest-scans"></tbody>
|
|
</table>
|
|
</div>
|
|
{% endblock %} {% block scripts %}
|
|
<script>
|
|
async function loadDashboard() {
|
|
try {
|
|
const s = await api("/api/status");
|
|
renderCards(s);
|
|
renderScans(s.latest_scans || []);
|
|
} catch (e) {
|
|
toast(e.message, "error");
|
|
}
|
|
}
|
|
|
|
function renderCards(s) {
|
|
const cards = [
|
|
{
|
|
label: "Scan running",
|
|
value: s.scan_running ? "Yes" : "No",
|
|
tone: s.scan_running ? "warn" : "ok",
|
|
},
|
|
{ label: "Blocklist IPv4", value: s.blocklist_ipv4_count ?? "—" },
|
|
{ label: "Blocklist IPv6", value: s.blocklist_ipv6_count ?? "—" },
|
|
{
|
|
label: "Firewall snapshot",
|
|
value:
|
|
s.firewall_snapshot && s.firewall_snapshot.exists
|
|
? "Present"
|
|
: "None",
|
|
tone:
|
|
s.firewall_snapshot && s.firewall_snapshot.exists ? "ok" : "muted",
|
|
},
|
|
];
|
|
if (s.analysis && s.analysis.available) {
|
|
cards.push({
|
|
label: "SQLite stores",
|
|
value: `${s.analysis.request_count ?? 0} req / ${s.analysis.scan_count ?? 0} scans`,
|
|
tone: "ok",
|
|
});
|
|
}
|
|
const box = document.getElementById("status-cards");
|
|
box.innerHTML = "";
|
|
for (const c of cards) {
|
|
box.append(
|
|
el(
|
|
"div",
|
|
{ class: "card" },
|
|
el("div", { class: "card-label", text: c.label }),
|
|
el("div", { class: `card-value ${c.tone || ""}`, text: c.value }),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
function renderScans(scans) {
|
|
const body = document.getElementById("latest-scans");
|
|
body.innerHTML = "";
|
|
if (!scans.length) {
|
|
body.innerHTML =
|
|
'<tr><td colspan="6" class="muted">No scans yet — run one from the Scan page.</td></tr>';
|
|
return;
|
|
}
|
|
for (const j of scans) {
|
|
const r = j.result || {};
|
|
body.append(
|
|
el(
|
|
"tr",
|
|
el("td", { class: "mono", text: j.job_id }),
|
|
el("td", { text: j.kind }),
|
|
el("td", {}, badge(j.state)),
|
|
el("td", { text: fmtTime(j.started) }),
|
|
el("td", { text: fmtTime(j.finished) }),
|
|
el("td", { class: "num", text: r.blocked_targets ?? "—" }),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
loadDashboard();
|
|
// Keep the latest-scans table fresh without hammering /api/scan/status.
|
|
setInterval(loadDashboard, 15000);
|
|
</script>
|
|
{% endblock %}
|