9.5 KiB
Pineapple UI Clone — Design Spec
- Date: 2026-08-11
- Status: Approved (pending written-spec review)
- Owner: Hak5 WiFi Pineapple Pager expansion project
- Supercedes look of:
www/assets shipped in2026-08-10-pager-webui-design.md
1. Goal
Restyle the Pager WebUI (http://172.16.52.1:8080/) to be a faithful clone of
the stock Hak5 WiFi Pineapple UI (http://172.16.42.1:1471/), so an operator
used to one interface can use the other without re-learning navigation,
terminology, or interaction patterns.
Scope is cosmetic + navigation only, plus one small read-only backend
endpoint (GET /api/pineap/aps, §3.5). Auth/session mechanics and the payload
packaging pipeline are unchanged.
Verified on-device (2026-08-11): the Pager's Go daemon on :1471 exposes only
api_ping, login, payload-portal, loot, and WS endpoints — it has no
/api/pineap/* surface. All PineAP/Recon/Logging/Settings endpoints in the
current server.py are implemented by pager-webui itself via hak5cmd,
uci, iwinfo, and recon.db. (Note: the old UI at 172.16.42.1:1471 and
the new Pager at 172.16.52.1 are separate devices.)
2. Research Basis (live UIs, captured 2026-08-11)
Old UI (:1471) — stock Angular 8 / Angular Material SPA
- Hash routes:
#/Login,#/Setup,#/Dashboard,#/Campaigns(/reports),#/Recon(/handshakes),#/PineAP(/open,/clients,/filtering,/enterprise,/aps,/impersonation),#/Settings(/networking,/wifi,/developer,/advanced,/led,/help),#/Logging(/system),#/Modules. - Login: full-screen flat gray
#9c9c9c; centered white elevated card (mat-elevation-z20): "WiFi Pineapple"h2, pineapple logo PNG (148px), Username + Password fields, raised "Login" button (spinner while busy), inline red error text; Cloud C2 error variant. - Shell: 64px toolbar (
#424242, Materialmat-toolbar) with logo + "WiFi Pineapple"; content offsetmargin-left: 90px; icon rail sidenav (min-width:60px,#f3f3f3; dark#3a3a3a, hover#a9a9a9/ dark#545454): Dashboard, Campaigns, PineAP ("PineAP Suite"), Recon, Logging, Modules ("Modules & Packages"), Settings; active entryborder-right:3px solid #1976d2; entry dividers; bottom "Open Menu" chevron toggles expanded rail; module entries are drag-reorderable (out of scope). Content background#fafafa; Roboto/Helvetica/sans-serif font stack. - Views use horizontal
mat-tabnavigation with a blue ink bar for each multi-page section (PineAP, Recon, Logging, Settings, Campaigns). - Dashboard: status cards (Clients, Handshakes Captured, Disk Usage, …) + Chart.js line chart (clients over time) + "Connected Clients" table (Deauthenticate) + "Captured WPA Handshakes" table.
- Extras: keyboard shortcuts (
D/C/R/P/M, Backquote = terminal), light/dark theme (stored inlocalStorage), notification center, corner "flash indicator" toasts, ASCII pineapple(='.'=). - Auth:
POST /api/login{username, password}→{token}; stored inlocalStorage<base>_authToken+AUTH_<ServerId>cookie; device password for userroot.
New UI (:8080) — vanilla JS SPA (current source of truth)
- GitHub-dark theme (
#0d1117bg,#161b22panels, teal#00d4aaaccent, Segoe UI); password-only login; flat text rail (Dashboard, PineAP, Recon, Handshakes, Payloads, Logs, Settings); single-page sections; bottom-docked xterm panel; WS live updates + 5s polling fallback; bottom-right toasts. - Backend: pure-socket HTTP/JSON/WS on
0.0.0.0:8080(devicepython3-light); auth viaAUTH_<serverid>HttpOnly cookie validated against the daemon; terminal connects directly to daemon WS on:1471.
Feature mapping (old IA → current Pager capabilities)
| Old tab | Clone behaviour |
|---|---|
| Dashboard | status cards + Chart.js chart + Connected Clients + Handshakes tables |
| Campaigns | visible tab, single "not supported on the Pager" empty-state card |
| PineAP → Open | PineAP settings toggles (mimic/advertise/probes/handshakes/random MAC/WiGLE) + bands |
| PineAP → Clients | connected clients + kick |
| PineAP → Filtering | client (MAC) + SSID allow/deny/off filters |
| PineAP → APs | new read-only endpoint GET /api/pineap/aps: iwinfo <mon-iface> scan table (BSSID/SSID/Channel/Signal/Encryption) |
| PineAP → Impersonation | SSID pool add/clear + Start/Stop/Collect |
| PineAP → Enterprise | omitted (not supported on Pager) |
| Recon → Overview | scans list + new/stop/refresh + scan detail |
| Recon → Handshakes | loot files: download zip / archive / delete |
| Logging → Overview | system + PineAP logs |
| Logging → System | system log with level filter (Error/Warning/Informational) |
| Modules & Packages | payload portal (search + list + Install/Remove) |
| Settings | general info, hostname, NTP, password, WebUI prefs (poll interval, theme) |
3. Design
3.1 Architecture
No build step; same vanilla-JS file layout. New/vendored files under www/:
assets/logo.png+ favicon — copied from old UIassets/icons/logo.png.js/chart.min.js— vendored Chart.js from old UI (no CDN on device).js/icons.js— inline SVG icon set lifted from the old Angular bundle (dashboard grid, campaigns, pineap, recon, logging, modules, settings, chevron).js/themes.cssor CSS custom properties — light/dark token sets.css/app.css— rewritten around Material light tokens.js/views.js— restructured to old IA with sub-views +mat-tab-style bars.js/app.js— routing (incl. sub-routes), keyboard shortcuts, theme toggle, terminal wiring, flash-style toasts.index.html— old-style shell markup (login card, toolbar, icon rail, content, terminal panel).
Roboto: vendor .woff2 from the device if present (:1471/assets/ fonts);
otherwise the existing Roboto, Helvetica Neue, sans-serif stack falls back to
system fonts.
3.2 Design tokens (light default, dark optional)
- Light: content
#fafafa; cards#fffwith subtle elevation/shadow; toolbar- rail
#424242; rail hover#a9a9a9; active border#1976d2; primary#1976d2/#1e88e5; danger#d32f2f; ok#7cb342; warn#f9a825; text#212121/ muted#686868; ink bar + focus#1976d2.
- rail
- Dark (mirrors old theme): rail
#3a3a3a, hover#545454, surfaces#303030, cards#424242. - Theme selected via
<html class="dark">driven bylocalStorage; toggle in Settings (and honored on all pages).
3.3 Shell
- Toolbar (64px,
#424242): logo + "WiFi Pineapple" brand (left); right: muted live status "BAT % · CLIENTS n", Terminal button. - Icon rail (60px): 7 entries, 24px inline SVG + label (label hidden while
collapsed,
titletooltip shown), dividers between groups, active = 3px blue right border. Bottom "Open Menu" chevron expands to ~200px with labels; state persisted inlocalStorage(mirrors oldsideNavState). - Content (
#fafafa): page header + horizontal tab bar (where applicable)- white cards; existing
.section/.tbl/.badge/.row/.toggleclasses restyled to the light theme.
- white cards; existing
- Terminal: stays bottom-docked (new behaviour) but restyled to the old look; kept docked intentionally (matches current Pager UX and spec v1).
- Toasts: corner "flash indicator" style (old look), same API.
3.4 Login
Password-only (per user decision; username fixed root). Full-screen gray
#9c9c9c; centered white elevated card: logo, "WiFi Pineapple" h2, single
Password field (placeholder "Password"), raised primary Login button with busy
spinner, inline red error text on failure. Posts to the existing /api/login
endpoint via PagerAPI.login('root', pw) — no backend change.
3.5 Views (per mapping table)
Each multi-page section renders a mat-tab-style horizontal bar (blue ink
bar) with tab items; deep-linkable via hash routes #/pineap/clients etc.
Placeholder Campaigns uses the old empty-state card.
PineAP → APs requires one new backend route. Add to server.py:
GET /api/pineap/aps → runs iwinfo <iface> scan over the monitor interfaces
listed by /api/status and returns rows {bssid, ssid, channel, signal, encryption} (read-only, no root action, same exposure class as the existing
/api/status). A unit test covers the parser with a canned iwinfo capture.
3.6 Data flow
Unchanged: PagerAPI (fetch wrapper), Live WS + 5s poll fallback, Live.onTick
drives the dashboard chart's rolling series (e.g. last 60 samples of clients +
handshakes). Theme and rail state live in localStorage. The single new route
is GET /api/pineap/aps (§3.5).
3.7 Error handling
Unchanged: failed API calls surface via toasts; login failure shows inline red text; WS down → poll fallback (existing logic untouched).
4. Testing
- Manual on-device smoke pass per spec v1 §8: every page in background and foreground modes, login/logout, terminal I/O, reboot persistence.
- Visual parity checklist: login card, toolbar, rail expand/collapse + active indicator, each tab bar, table/card styling, dark theme.
- Asset checks:
logo.png, favicon,chart.min.js, Roboto (if vendored) all serve from:8080; verify withcurl. - Existing Python
unittestsuite (API-level) must remain green; add a test for the newiwinfoscan parser. - Deploy via
scripts/deploy.ps1(existing pipeline); payload zip must include the new/vendored assets.
5. Out of scope
- Campaigns functionality, Cloud C2, Enterprise SSIDs, LED/Network/Developer
Settings sub-pages, module drag-reorder, notification center,
:1471takeover.