2026-04-03 14:38:38 +03:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="en">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8" />
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
|
|
|
<title>ESP32 Recon</title>
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
2026-04-04 12:47:43 +03:00
|
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" />
|
2026-04-03 14:38:38 +03:00
|
|
|
|
<link rel="stylesheet" href="/static/dashboard.css" />
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<div id="app">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Topbar -->
|
|
|
|
|
|
<div id="topbar">
|
|
|
|
|
|
<span class="title">ESP32 Recon</span>
|
|
|
|
|
|
<span class="sep">/</span>
|
|
|
|
|
|
<span class="build-info">WiFi Recon Cluster</span>
|
|
|
|
|
|
<div id="live-dot"></div>
|
|
|
|
|
|
<span id="live-label">LIVE</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Navbar -->
|
|
|
|
|
|
<div id="navbar">
|
|
|
|
|
|
<button class="tab-btn active" id="tab-feed" onclick="showFeed()">Feed</button>
|
|
|
|
|
|
<button class="tab-btn" id="tab-networks" onclick="showNetworks()">Networks</button>
|
|
|
|
|
|
<button class="tab-btn" id="tab-crossnode" onclick="showCrossNode()">Cross-node</button>
|
|
|
|
|
|
<button class="tab-btn" id="tab-clients" onclick="showClients()">Clients</button>
|
2026-04-03 21:50:41 +03:00
|
|
|
|
<button class="tab-btn" id="tab-presence" onclick="showPresence()">Presence</button>
|
2026-04-03 22:24:25 +03:00
|
|
|
|
<button class="tab-btn" id="tab-alerts" onclick="showAlerts()">Alerts</button>
|
2026-04-05 11:29:59 +03:00
|
|
|
|
<button class="tab-btn" id="tab-analysis" onclick="showAnalysis()">Analysis</button>
|
2026-04-04 12:47:43 +03:00
|
|
|
|
<button class="tab-btn" id="tab-search" onclick="showSearch()">Search</button>
|
2026-04-03 14:38:38 +03:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Sidebar -->
|
|
|
|
|
|
<div id="sidebar">
|
|
|
|
|
|
<div class="sidebar-section">
|
|
|
|
|
|
<div class="sidebar-label">Summary</div>
|
|
|
|
|
|
<div class="stat-row"><span>nodes</span><span id="sum-nodes">—</span></div>
|
|
|
|
|
|
<div class="stat-row"><span>online</span><span id="sum-online">—</span></div>
|
|
|
|
|
|
<div class="stat-row"><span>events (session)</span><span id="sum-events">—</span></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="sidebar-section">
|
|
|
|
|
|
<div class="sidebar-label">Nodes</div>
|
|
|
|
|
|
<div id="node-list"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Main -->
|
|
|
|
|
|
<div id="main">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Feed view -->
|
|
|
|
|
|
<div id="view-general" class="view active">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Live Feed</span>
|
|
|
|
|
|
<span class="section-count" id="general-count"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>Time</th>
|
|
|
|
|
|
<th>Node</th>
|
|
|
|
|
|
<th>SSID</th>
|
|
|
|
|
|
<th>BSSID</th>
|
|
|
|
|
|
<th>RSSI</th>
|
|
|
|
|
|
<th>Ch</th>
|
|
|
|
|
|
<th>Enc</th>
|
|
|
|
|
|
<th>Imp</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="general-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="general-empty" style="display:none">No events yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Node detail view -->
|
|
|
|
|
|
<div id="view-detail" class="view">
|
|
|
|
|
|
<button id="back-btn" onclick="showGeneral()">← All nodes</button>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Node</span>
|
|
|
|
|
|
<span class="section-count" id="detail-node-id"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div id="detail-stats-grid">
|
2026-04-04 12:47:43 +03:00
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Status</div><div class="value" id="ds-status">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Total Events</div><div class="value" id="ds-total">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Unique SSIDs</div><div class="value" id="ds-ssids">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Unique BSSIDs</div><div class="value" id="ds-bssids">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Avg RSSI</div><div class="value" id="ds-rssi-avg">—</div><div class="sub" id="ds-rssi-range"></div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">First Seen</div><div class="value value-sm" id="ds-first">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Last Seen</div><div class="value value-sm" id="ds-last">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Uptime</div><div class="value" id="ds-uptime">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">Free Heap</div><div class="value" id="ds-heap">—</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
|
|
|
|
|
<div class="stat-outer"><div class="stat-dot"></div><div class="stat-card"><div class="stat-ray"></div><div class="label">AP Signal</div><div class="value" id="ds-ap-rssi">—</div><div class="sub">node → router</div><div class="line topl"></div><div class="line leftl"></div><div class="line bottoml"></div><div class="line rightl"></div></div></div>
|
2026-04-03 14:38:38 +03:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="section-header" style="margin-top:4px">
|
|
|
|
|
|
<span class="section-title">Recent Events</span>
|
|
|
|
|
|
<span class="section-count" id="detail-count"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>Time</th>
|
|
|
|
|
|
<th>SSID</th>
|
|
|
|
|
|
<th>BSSID</th>
|
|
|
|
|
|
<th>RSSI</th>
|
|
|
|
|
|
<th>Ch</th>
|
|
|
|
|
|
<th>Enc</th>
|
|
|
|
|
|
<th>Imp</th>
|
|
|
|
|
|
<th>Conf</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="detail-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Clients view -->
|
|
|
|
|
|
<div id="view-clients" class="view">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Client Devices</span>
|
|
|
|
|
|
<span class="section-count" id="clients-count"></span>
|
|
|
|
|
|
<span style="margin-left:auto; font-size:10px; color:var(--text-muted)">
|
|
|
|
|
|
note: modern devices use randomised MACs — one physical device may appear as multiple entries
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>MAC</th>
|
|
|
|
|
|
<th>Vendor</th>
|
|
|
|
|
|
<th>Probing for</th>
|
|
|
|
|
|
<th>Best RSSI</th>
|
|
|
|
|
|
<th>Avg RSSI</th>
|
|
|
|
|
|
<th>Nodes</th>
|
|
|
|
|
|
<th>Times Seen</th>
|
|
|
|
|
|
<th>Last Seen</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="clients-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="clients-empty" style="display:none">No probe events yet. Nodes need to be flashed with probe sniffing enabled.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Cross-node view -->
|
|
|
|
|
|
<div id="view-crossnode" class="view">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Cross-node RSSI</span>
|
|
|
|
|
|
<span class="section-count" id="crossnode-count"></span>
|
|
|
|
|
|
<label style="margin-left:auto; font-size:10px; color:var(--text-dim); display:flex; align-items:center; gap:6px; cursor:pointer;">
|
|
|
|
|
|
<input type="checkbox" id="crossnode-filter" onchange="renderCrossNodeTable()" style="accent-color:var(--green-hi)">
|
|
|
|
|
|
multi-node only
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table id="crossnode-table">
|
|
|
|
|
|
<thead id="crossnode-thead"></thead>
|
|
|
|
|
|
<tbody id="crossnode-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="crossnode-empty" style="display:none">No data yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Network RSSI chart view -->
|
|
|
|
|
|
<div id="view-network-chart" class="view">
|
|
|
|
|
|
<button class="back-btn" onclick="showNetworks()">← Networks</button>
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title" id="chart-title">RSSI History</span>
|
|
|
|
|
|
<span class="section-count" id="chart-subtitle"></span>
|
|
|
|
|
|
<div class="range-btns" style="margin-left:auto">
|
|
|
|
|
|
<button class="range-btn" data-hours="1" onclick="setChartRange(1)">1h</button>
|
|
|
|
|
|
<button class="range-btn active" data-hours="2" onclick="setChartRange(2)">2h</button>
|
|
|
|
|
|
<button class="range-btn" data-hours="6" onclick="setChartRange(6)">6h</button>
|
|
|
|
|
|
<button class="range-btn" data-hours="24" onclick="setChartRange(24)">24h</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="chart-legend"></div>
|
|
|
|
|
|
<canvas id="rssi-chart" height="240"></canvas>
|
|
|
|
|
|
<div class="empty" id="chart-empty" style="display:none">No data for this time range.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Networks view -->
|
|
|
|
|
|
<div id="view-networks" class="view">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Networks</span>
|
|
|
|
|
|
<span class="section-count" id="networks-count"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th class="sortable" data-col="ssid" data-arrow="">SSID</th>
|
|
|
|
|
|
<th class="sortable" data-col="bssid" data-arrow="">BSSID</th>
|
|
|
|
|
|
<th class="sortable" data-col="best_rssi" data-arrow="">Best RSSI</th>
|
|
|
|
|
|
<th class="sortable" data-col="avg_rssi" data-arrow="">Avg RSSI</th>
|
|
|
|
|
|
<th class="sortable" data-col="channel" data-arrow="">Ch</th>
|
|
|
|
|
|
<th class="sortable" data-col="encryption" data-arrow="">Enc</th>
|
|
|
|
|
|
<th class="sortable sort-active" data-col="times_seen" data-arrow="↓">Times Seen</th>
|
|
|
|
|
|
<th class="sortable" data-col="node_count" data-arrow="">Nodes</th>
|
|
|
|
|
|
<th class="sortable" data-col="last_seen" data-arrow="">Last Seen</th>
|
|
|
|
|
|
<th></th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="networks-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="networks-empty" style="display:none">No networks seen yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-03 21:50:41 +03:00
|
|
|
|
<!-- Presence view -->
|
|
|
|
|
|
<div id="view-presence" class="view">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Present now -->
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Present Now</span>
|
|
|
|
|
|
<span class="section-count" id="present-count"></span>
|
|
|
|
|
|
<span class="presence-sub">real MACs · seen 2+ times in last hour</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>MAC</th><th>Vendor</th><th>Best RSSI</th><th>Avg RSSI</th>
|
|
|
|
|
|
<th>Times Seen</th><th>Nodes</th><th>Last Seen</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="present-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="present-empty" style="display:none">No devices currently present.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- New arrivals -->
|
|
|
|
|
|
<div class="section-header" style="margin-top:8px">
|
|
|
|
|
|
<span class="section-title">New Arrivals</span>
|
|
|
|
|
|
<span class="section-count" id="arrivals-count"></span>
|
|
|
|
|
|
<span class="presence-sub">first seen in last 24h</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="presence-split">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="presence-sub-label">Devices</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>MAC</th><th>Vendor</th><th>First Seen</th>
|
|
|
|
|
|
<th>Best RSSI</th><th>Times Seen</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="arrivals-macs-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="arrivals-macs-empty" style="display:none">No new devices.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="presence-sub-label">Networks</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>SSID</th><th>BSSID</th><th>First Seen</th>
|
|
|
|
|
|
<th>Best RSSI</th><th>Ch</th><th>Enc</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="arrivals-nets-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="arrivals-nets-empty" style="display:none">No new networks.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Regulars -->
|
|
|
|
|
|
<div class="section-header" style="margin-top:8px">
|
|
|
|
|
|
<span class="section-title">Regulars</span>
|
|
|
|
|
|
<span class="section-count" id="regulars-count"></span>
|
|
|
|
|
|
<span class="presence-sub">seen on 2+ distinct days</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="presence-split">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="presence-sub-label">Devices</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>MAC</th><th>Vendor</th><th>Days Seen</th>
|
|
|
|
|
|
<th>First Seen</th><th>Last Seen</th><th>Best RSSI</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="regulars-macs-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="regulars-macs-empty" style="display:none">Regulars appear after 2+ days of data.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="presence-sub-label">Networks</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>SSID</th><th>BSSID</th><th>Days Seen</th>
|
|
|
|
|
|
<th>First Seen</th><th>Best RSSI</th><th>Ch</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="regulars-nets-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="regulars-nets-empty" style="display:none">Regulars appear after 2+ days of data.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- /#view-presence -->
|
|
|
|
|
|
|
2026-04-03 22:24:25 +03:00
|
|
|
|
<!-- Alerts view -->
|
|
|
|
|
|
<div id="view-alerts" class="view">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Summary strip -->
|
|
|
|
|
|
<div id="alerts-summary" class="alerts-summary"></div>
|
|
|
|
|
|
|
2026-04-04 12:47:43 +03:00
|
|
|
|
<!-- Top targets / attackers -->
|
|
|
|
|
|
<div class="presence-split" style="margin-top:8px">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Most Impersonated Networks</span>
|
|
|
|
|
|
<span class="section-count" id="targets-count"></span>
|
|
|
|
|
|
<span class="presence-sub">all time · APs spoofed as deauth source</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>BSSID</th><th>SSID</th><th>Frames</th>
|
|
|
|
|
|
<th>Unique Srcs</th><th>Nodes</th><th>Last Seen</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="targets-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="targets-empty" style="display:none">No data yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Most Targeted Devices</span>
|
|
|
|
|
|
<span class="section-count" id="attackers-count"></span>
|
|
|
|
|
|
<span class="presence-sub">all time · actual victim devices by dst MAC</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>Dst MAC</th><th>Vendor</th><th>Frames</th>
|
|
|
|
|
|
<th>Networks Used</th><th>Nodes</th><th>Last Seen</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="attackers-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="attackers-empty" style="display:none">No data yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-05 11:29:59 +03:00
|
|
|
|
<!-- Reason code breakdown -->
|
|
|
|
|
|
<div class="section-header" style="margin-top:8px">
|
|
|
|
|
|
<span class="section-title">Reason Code Breakdown</span>
|
|
|
|
|
|
<span class="section-count" id="reasons-count"></span>
|
|
|
|
|
|
<span class="presence-sub">all time · normal / suspicious / attack classification</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>Code</th><th>Description</th><th>Class</th>
|
|
|
|
|
|
<th>Frames</th><th>Unique BSSIDs</th><th>Unique Targets</th><th>Last Seen</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="reasons-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="reasons-empty" style="display:none">No data yet.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-03 22:24:25 +03:00
|
|
|
|
<!-- Detected bursts -->
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Detected Bursts</span>
|
|
|
|
|
|
<span class="section-count" id="bursts-count"></span>
|
|
|
|
|
|
<span class="presence-sub">≥10 deauth/disassoc frames for same BSSID in last 5 min</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>BSSID</th><th>SSID</th><th>Type</th><th>Frames</th>
|
|
|
|
|
|
<th>Unique Srcs</th><th>Nodes</th><th>First</th><th>Last</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="bursts-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="bursts-empty" style="display:none">No bursts detected in last 5 minutes.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Raw deauth feed -->
|
|
|
|
|
|
<div class="section-header" style="margin-top:8px">
|
|
|
|
|
|
<span class="section-title">Recent Deauth / Disassoc Events</span>
|
|
|
|
|
|
<span class="section-count" id="deauth-count"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbl-wrap">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr>
|
|
|
|
|
|
<th>Time</th><th>Node</th><th>Type</th><th>Src</th>
|
|
|
|
|
|
<th>Dst</th><th>BSSID</th><th>Reason</th><th>RSSI</th>
|
|
|
|
|
|
</tr></thead>
|
|
|
|
|
|
<tbody id="deauth-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="empty" id="deauth-empty" style="display:none">No deauth events yet. Nodes need to be reflashed with deauth detection enabled.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- /#view-alerts -->
|
|
|
|
|
|
|
2026-04-05 11:29:59 +03:00
|
|
|
|
<!-- Analysis view -->
|
|
|
|
|
|
<div id="view-analysis" class="view">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Deauth activity heatmap -->
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span class="section-title">Deauth Activity Heatmap</span>
|
|
|
|
|
|
<span class="section-count" id="heatmap-subtitle"></span>
|
|
|
|
|
|
<span class="presence-sub">frame count per day × hour — pattern reveals manual vs automated activity</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<canvas id="deauth-heatmap"></canvas>
|
|
|
|
|
|
<div class="empty" id="heatmap-empty" style="display:none">No deauth data yet.</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- /#view-analysis -->
|
|
|
|
|
|
|
2026-04-04 12:47:43 +03:00
|
|
|
|
<!-- Search view -->
|
|
|
|
|
|
<div id="view-search" class="view">
|
|
|
|
|
|
<div class="search-bar">
|
|
|
|
|
|
<input type="text" id="search-input" class="search-input"
|
|
|
|
|
|
placeholder="MAC address, SSID, BSSID — full or partial..."
|
|
|
|
|
|
onkeydown="if(event.key==='Enter') doSearch()" />
|
|
|
|
|
|
<button class="search-btn" onclick="doSearch()">Search</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="search-results">
|
|
|
|
|
|
<div class="empty" id="search-empty">Enter a value above to search across all collected data.</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-04-03 14:38:38 +03:00
|
|
|
|
</div><!-- /#main -->
|
|
|
|
|
|
</div><!-- /#app -->
|
|
|
|
|
|
|
|
|
|
|
|
<script src="/static/dashboard.js"></script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|