diff --git a/payload/user/remote_access/pager-webui/www/css/app.css b/payload/user/remote_access/pager-webui/www/css/app.css index 82242eb..476f712 100644 --- a/payload/user/remote_access/pager-webui/www/css/app.css +++ b/payload/user/remote_access/pager-webui/www/css/app.css @@ -326,6 +326,11 @@ html.dark .muted { color: #bdbdbd; } .recon-chart-box { position: relative; flex: 1; min-height: 0; margin-top: auto; } .recon-chart-box canvas { position: absolute; inset: 0; width: 100%; height: 100%; } .recon-no-data { font-style: italic; color: #787878; display: flex; justify-content: center; align-items: center; padding: 8px; text-align: center; } +.recon-enc-legend { display: flex; flex-wrap: wrap; gap: 2px 10px; margin-top: 4px; align-items: baseline; } +.recon-enc-entry { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--text); } +.recon-enc-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; } +.recon-enc-label { color: var(--muted); } +.recon-enc-count { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; } .recon-hs-count { font-size: 32px; font-weight: 700; line-height: 1.1; } .recon-hs-label { color: var(--muted); font-size: 12px; margin: 1px 0 8px; } .recon-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text); margin: 0; cursor: pointer; } diff --git a/payload/user/remote_access/pager-webui/www/js/views.js b/payload/user/remote_access/pager-webui/www/js/views.js index b23c0f0..caba63e 100644 --- a/payload/user/remote_access/pager-webui/www/js/views.js +++ b/payload/user/remote_access/pager-webui/www/js/views.js @@ -1495,16 +1495,14 @@ views.recon = (root) => { chanBox.appendChild(chanEmpty); const encBody = titleCard('Encryption Landscape', null); - const encValue = h('div', { class: 'recon-card-value', text: '—' }); - const encSub = h('div', { class: 'recon-card-sub', text: '' }); - encBody.appendChild(encValue); - encBody.appendChild(encSub); const encBox = h('div', { class: 'recon-chart-box' }); encBody.appendChild(encBox); const encCanvas = h('canvas', { id: 'recon-encryption' }); encBox.appendChild(encCanvas); const encEmpty = h('div', { class: 'recon-no-data', text: 'No encryption data yet — run a scan.' }); encBox.appendChild(encEmpty); + const encLegend = h('div', { class: 'recon-enc-legend' }); + encBody.appendChild(encLegend); const hsBody = titleCard('Handshakes', '#/recon/handshakes'); const hsCount = h('span', { class: 'recon-hs-count', text: '0' }); @@ -2258,12 +2256,6 @@ views.recon = (root) => { const b = reconEncBucket(a.encryption); encCounts[b] = (encCounts[b] || 0) + 1; }); - let topEnc = null, topEncN = 0; - Object.keys(encCounts).forEach((k) => { - if (encCounts[k] > topEncN) { topEnc = k; topEncN = encCounts[k]; } - }); - encValue.textContent = topEnc || '—'; - encSub.textContent = topEnc ? topEncN + ' of ' + n + ' APs' : ''; const land = document.getElementById('recon-landscape'); if (land && typeof MiniChart !== 'undefined' && MiniChart.doughnut) { @@ -2311,7 +2303,7 @@ views.recon = (root) => { if (aps.length) { MiniChart.doughnut(enc, RECON_ENC_BUCKETS.map((k, i) => ({ label: k, value: encCounts[k] || 0, color: RECON_ENC_COLORS[i] - })), { legend: true, height: 66 }); + })), { legend: false, height: 120 }); enc.classList.remove('hidden'); encEmpty.classList.add('hidden'); } else { @@ -2320,6 +2312,21 @@ views.recon = (root) => { } } catch (e) {} } + const encLegend = document.getElementById('recon-enc-legend'); + if (encLegend) { + encLegend.innerHTML = ''; + RECON_ENC_BUCKETS.forEach((k, i) => { + const c = encCounts[k] || 0; + if (!c) return; + const entry = h('div', { class: 'recon-enc-entry' }); + const dot = h('span', { class: 'recon-enc-dot' }); + dot.style.background = RECON_ENC_COLORS[i]; + entry.appendChild(dot); + entry.appendChild(h('span', { class: 'recon-enc-label', text: k })); + entry.appendChild(h('span', { class: 'recon-enc-count', text: String(c) })); + encLegend.appendChild(entry); + }); + } } function detailUrl() {