# 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 in `2026-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`, Material `mat-toolbar`) with logo + "WiFi Pineapple"; content offset `margin-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 entry `border-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-tab` navigation 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 in `localStorage`), notification center, corner "flash indicator" toasts, ASCII pineapple `(='.'=)`. - **Auth:** `POST /api/login` `{username, password}` → `{token}`; stored in `localStorage` `_authToken` + `AUTH_` cookie; device password for user `root`. ### New UI (:8080) — vanilla JS SPA (current source of truth) - GitHub-dark theme (`#0d1117` bg, `#161b22` panels, teal `#00d4aa` accent, 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` (device `python3-light`); auth via `AUTH_` 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 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 UI `assets/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.css` or 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 `#fff` with 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`. - Dark (mirrors old theme): rail `#3a3a3a`, hover `#545454`, surfaces `#303030`, cards `#424242`. - Theme selected via `` driven by `localStorage`; 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, `title` tooltip shown), dividers between groups, active = 3px blue right border. Bottom "Open Menu" chevron expands to ~200px with labels; state persisted in `localStorage` (mirrors old `sideNavState`). - **Content (`#fafafa`):** page header + horizontal tab bar (where applicable) + white cards; existing `.section`/`.tbl`/`.badge`/`.row`/`.toggle` classes restyled to the light theme. - **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 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 with `curl`. - Existing Python `unittest` suite (API-level) must remain green; add a test for the new `iwinfo` scan 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, `:1471` takeover.