/* ESPILON Honeypot Dashboard — Sidebar Renders */ import { S } from './state.js'; import { $id, escHtml, formatTime, countryFlag, sevColor, layerForType, layerColor, emptyState } from './utils.js'; import { renderSevDonut } from './charts.js'; // ── Severity Stats ────────────────────────────────────────── export function renderSevStats() { const el = $id('sev-stats'); if (!el) return; const bySev = (S.stats && S.stats.by_severity) ? S.stats.by_severity : {}; const sevs = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']; const counts = []; let total = 0; for (let i = 0; i < sevs.length; i++) { const c = bySev[sevs[i]] || 0; counts.push(c); total += c; } let html = ''; // Donut placeholder html += '
'; // Count list html += '
'; for (let i = 0; i < sevs.length; i++) { html += '
'; html += '' + sevs[i] + ''; html += '' + counts[i] + ''; html += '
'; } html += '
'; el.innerHTML = html; // Render donut into the container const donutEl = $id('sev-donut-sb'); if (donutEl) { const statsObj = {}; for (let i = 0; i < sevs.length; i++) statsObj[sevs[i]] = counts[i]; renderSevDonut(donutEl, statsObj); } } // ── Layer Stats ───────────────────────────────────────────── export function renderLayerStats() { const el = $id('layer-stats'); if (!el) return; const layerCounts = { L2: 0, L3: 0, L4: 0, L7: 0 }; if (S.events) { for (let i = 0; i < S.events.length; i++) { const l = layerForType(S.events[i].event_type); if (layerCounts[l] !== undefined) layerCounts[l]++; } } const layers = ['L2', 'L3', 'L4', 'L7']; let html = '
'; for (let i = 0; i < layers.length; i++) { const l = layers[i]; html += '
'; html += '
' + layerCounts[l] + '
'; html += '
' + l + '
'; html += '
'; } html += '
'; el.innerHTML = html; } // ── Attackers ─────────────────────────────────────────────── export function renderAttackers() { const el = $id('attackers-list'); if (!el) return; const list = S.attackers || []; const top = list.slice(0, 10); if (!top.length) { el.innerHTML = emptyState('\u{1F464}', 'No attackers yet', ''); return; } const maxCount = top[0].total_events || top[0].count || 1; let html = ''; for (let i = 0; i < top.length; i++) { const a = top[i]; const cnt = a.total_events || a.count || 0; const pct = Math.round((cnt / maxCount) * 100); const flag = a.country_code ? countryFlag(a.country_code) + ' ' : ''; const vendor = a.vendor || ''; html += '
'; html += '
'; html += '' + flag + escHtml(a.ip) + ''; html += '' + cnt + ''; html += '
'; if (vendor) { html += '
' + escHtml(vendor) + '
'; } html += '
'; html += '
'; html += '
'; html += '
'; } el.innerHTML = html; } // ── Alerts ────────────────────────────────────────────────── export function renderAlerts() { const el = $id('alerts-list'); const badge = $id('alert-badge'); const banner = $id('alert-banner'); const bannerCount = $id('alert-banner-count'); const alerts = S.alerts || []; const unacked = alerts.filter(function(a) { return !a.acknowledged; }); // Badge if (badge) { badge.textContent = unacked.length; badge.style.display = unacked.length > 0 ? '' : 'none'; } // Banner if (banner) { banner.style.display = unacked.length > 0 ? '' : 'none'; } if (bannerCount) { bannerCount.textContent = unacked.length; } // List if (!el) return; if (!alerts.length) { el.innerHTML = emptyState('\u{1F514}', 'No alerts', ''); return; } let html = ''; for (let i = 0; i < alerts.length; i++) { const a = alerts[i]; const borderCol = sevColor(a.severity || 'MEDIUM'); const acked = a.acknowledged; html += '
'; html += '
'; html += '
' + escHtml(a.message || a.detail || 'Alert') + '
'; if (!acked) { html += ''; } html += '
'; if (a.timestamp) { html += '
' + formatTime(a.timestamp) + '
'; } html += '
'; } el.innerHTML = html; } // ── Command History ───────────────────────────────────────── export function renderHistory() { const el = $id('cmd-history'); if (!el) return; const list = S.history || []; const items = list.slice(0, 20); if (!items.length) { el.innerHTML = emptyState('\u{2328}\u{FE0F}', 'No commands yet', ''); return; } let html = ''; for (let i = 0; i < items.length; i++) { const h = items[i]; let statusDot; if (h.status === 'completed') { statusDot = 'var(--sev-low)'; } else if (h.status === 'pending' || h.status === 'sent') { statusDot = 'var(--sev-med)'; } else { statusDot = 'var(--sev-high)'; } let cmdName = h.command_name || h.command || '?'; if (cmdName.length > 24) cmdName = cmdName.substring(0, 24) + '\u2026'; const timeStr = h.sent_at ? formatTime(h.sent_at) : ''; html += '
'; html += ''; html += '' + escHtml(cmdName) + ''; html += '' + timeStr + ''; html += '
'; } el.innerHTML = html; } // ── Full Sidebar Render ───────────────────────────────────── export function renderSidebar() { renderSevStats(); renderLayerStats(); renderAttackers(); renderAlerts(); renderHistory(); }