- Top 5 recon cards restyled as stat cards: value + sub-line + mini chart, consistent 190px anatomy; Handshakes links to the handshakes page; Previous Scans shows count/latest plus a compact picker + action row - Channel map records lobe geometry (canvas.__reconLobes / __reconLobesHit); hovering lists the networks under the cursor, click pins the tooltip, mouseleave hides it; empty states hide the tooltip too - Recon focus sidebar gains 'Send to PineAP — Twin this network': routes to Evil WPA (psk2/sae/owe from recon encryption) or OpenAP (with BSSID) and prefills the form; one-shot PineAPPrefill is consumed by the attack launcher and never auto-deploys or leaks into manual forms - Existing Actions verified end-to-end and hardened: capture/stop handshake sync the auto-collect toggle, examine buttons disable while pending - Recon resilience: loadDetail retries after failed render or 503 (no more permanently blank page), scan-list errors surface in the scan bar, poll guard prevents overlapping loads, chart draws are individually isolated - Auto-collect toggle re-syncs from get_config on the slow poll so the UI tracks the pager's own settings
6.0 KiB
6.0 KiB
Mark VIII UI Hardening + Recon Polish — Design
Date: 2026-08-18 Status: Approved in advance by user (auto-approve; user unavailable for review)
Context
Mark VIII (web UI for the WiFi Pineapple Pager) has been through major dev changes. The user runs a live test tomorrow and needs the UI rock solid. Verified on device:
- MCP server works:
tools/listreturns 16 tools;device.state,recon.apsrespond correctly. - API endpoints used by the Recon "Actions" buttons work
(
/api/recon/examine,/api/pineap/set_config). - Recon detail endpoint is slow (~1.5 s) and can 503 when the sqlite DB is busy; the UI swallows errors silently and can stay blank.
Findings
- Recon top cards (5): equal 200 px cards with 20 px titles, centered content, charts sized for wide cards. "Previous Scans" crams 5 icon buttons + a 50+-option select into a ~220 px card → buttons stack into three rows. "Channel Distribution" bar chart is unreadable at card width. Handshakes toggle text wraps awkwardly.
- Channel map: canvas lobes render but have zero interactivity — no way to see which networks are under the cursor.
- Focus sidebar Actions: "Capture WPA Handshakes" / "Stop Handshake Capture" / "Examine BSSID" / "Examine Channel" work at the API level but give weak feedback; there is no path from a recon target to the PineAP evil-twin form.
- Robustness:
loadDetail()in the recon view swallows render/network errors with.catch(() => {}); if rendering throws afterdetailIdis set, the page stays blank forever (guard short-circuits).load()has no pending guard → overlapping polls.hsAuto(loghandshake) checkbox is only synced at view creation — it drifts from the pager's own settings when changed elsewhere (pager UI / another browser).
Changes
1. Recon title cards — redesign (views.js + app.css)
New card anatomy (all five consistent):
- Compact header: 12 px uppercase muted title (clickable where it links).
- Primary value: 28 px bold.
- Sub-line: 12 px muted context text.
- Optional mini chart: fixed 96 px tall.
Cards (flex: 1 1 0; min-width: 170px; height: 190px — five fit one row
even in a ~1000 px pane):
- Wireless Landscape — value: total networks (APs); sub: "N clients · M unassociated"; mini doughnut (APs/Clients/Unassociated).
- Channel Distribution — value: busiest channel "CH 6"; sub: "N of K APs on CH 6 · channels seen"; mini bar chart of channel counts.
- Encryption Landscape — value: top encryption bucket; sub: "N of K APs"; mini doughnut of buckets.
- Handshakes — value: handshake count (links to
#/recon/handshakes); sub: "captured"; auto-collect toggle (restyled). - Previous Scans — value: scan count; sub: latest scan start time; compact select row + single row of icon buttons.
Empty states get copy that matches the card ("No landscape data yet — run a scan").
2. Channel map hover (chart.js + views.js + app.css)
MiniChart.channelMaprecords per-lobe geometry on the canvas:canvas.__reconLobes = [{ ap, cx, half, topPx, basePx }](CSS px).views.jsattachesmousemove/mouseleave/clickto the map canvas:- hit test:
t=(mx-cx)/half, lift =0.5+0.5·cos(πt), hovered ifmy >= basePx - lift·peakPx - 4andmy <= basePx + 8; - tooltip div (absolute, inside
.recon-map-box) lists every network under the cursor: SSID/MAC/channel/freq/signal/encryption/vendor; - click pins the tooltip until the next move or click;
mouseleavehides it.
- hit test:
- Lobe geometry regenerates on every
renderChannelMap()(redraw), so stale geometry is impossible.
3. Focus sidebar: Actions validation + Send to PineAP (views.js)
- Existing buttons stay; toast feedback improved (already verified working at API level; re-verified end-to-end in browser).
- New primary button "Send to PineAP — Twin this network":
- encryption bucket
Open→ navigate#/pineap/openwith prefill{ssid, hidden, channel, bssid}; - anything else → navigate
#/pineap/evilwpawith prefill{ssid, hidden, channel, enctype}where enctype maps from recon encryption: SAE→sae, OWE→owe, WPA3-only→sae, elsepsk2; - Enterprise networks still go to Evil WPA (psk2) — noted in the prefill banner.
- encryption bucket
- Prefill mechanism:
window.PineAPPrefill = { set, consume }(module singleton inviews.js);consume()clears after use so a stale prefill never leaks into a manually opened form. attackLauncher()consumes the prefill when building the form (SSID, hidden, channel viachanSelect, enctype, BSSID) and renders a muted banner: "Prefilled from Recon — verify, set the passphrase, then Deploy." Deploy is never triggered automatically (no attacks without an explicit user action).
4. Robustness / sync hardening (views.js)
loadDetail(): on fetch failure keepdetailIdunset so the poll retries; surface "Scan data unavailable — retrying…" in the scan status line; wrap the render body so one chart's exception cannot blank the table (each chart draw also wrapped individually).drawCharts(): wrap each chart section in try/catch.load():loadPendingguard against overlapping polls; surface scan-list errors in the status line.hsAutore-syncs from/api/pineap/get_configon the 30 s slow poll (stays in sync with the pager's own UI/settings changes).- Version bumps in
index.htmlforapp.css,chart.js,views.js.
5. Verification
- Backend unchanged → existing
tests/still pass (run the suite). - Deploy via
scripts/deploy.sh --password(device: 172.16.52.1). - End-to-end in browser (device UI):
- login; recon page: cards populated with scan data; no blank-page state;
- click an AP row → focus sidebar → each Action button verified by
reading back state (
get_config) and API responses; - Send to PineAP → form pre-filled on the right tab (open vs WPA target);
- channel map click → tooltip shows networks under cursor;
- reboot-resilience spot check via service restart (pagerwebui restart).