9.6 KiB
Design: Mark VII PineAP Page Port for the Pager WebUI
Date: 2026-08-11
Goal
Replace the current pager-webui PineAP page with a faithful replica of the WiFi Pineapple Mark VII PineAP view, fully functional on the WiFi Pineapple Pager, independent of campaign needs. Also fix the side-rail icon (location pin -> wifi).
Background / findings
-
The current PineAP page (tabs: Open, Clients, Filtering, APs, Impersonation) looks nothing like the Mark VII page and its backend is broken on the Pager:
server.pyreads Mark VII uci keys (pineapd.pineapd.mimic,collect_handshakes, ...) that do not exist in the Pager'spineapdconfig, so settings never persist (liveGET /api/pineap/settingsreturns only{"bands":"2.4"}plus raw).- The filter-mode endpoints call
hak5cmdcommands without the required argument, returning usage text instead of the mode.
-
The Pager's daemon (
/pineapple/pineapple, listens on:1471) natively exposes a Mark VII-style PineAP REST API over a root-only unix socket at/tmp/api.sock(raw HTTP/1.1, no auth - socket permission is the boundary). pager-webui already uses this socket (daemon_sock_call, e.g. recon start/stop). Confirmed live routes:Route Method Purpose /api/pineap/get_config,/set_configGET/POST log flags, handshake path, ssidpool autocollect /api/pineap/hostapd/get_config,/set_configGET/POST master PineAP on/off, Evil WPA ( wpa_ifaces), Evil Enterprise (pineape_*)/api/pineap/hostapd/enable_pineapPOST master enable /api/pineap/hostapd/enable_pineapePOST evil enterprise enable /api/pineap/hostapd/enable_pineape_authPOST enterprise auth-pass capture /api/pineap/mimic/enable,/disablePOST karma /api/pineap/examine/bssid,/resetPOST targeted handshake capture /api/pineap/ssidpool/list,/add,/clear,/disable,/disable_collectGET/POST SSID pool + advertise/collect /api/pineap/ssidfilter/get_config,/set_config,/allow/*,/deny/*GET/POST SSID filter mode + lists /api/pineap/macfilter/get_config,/set_config,/set_mode,/allow/*,/deny/*GET/POST MAC/client filter mode + lists /api/pineap/interfaces/get,/set_interface,/set_interface_bandsGET/POST monitor interface hop/inject/bands `/api/pineap/log/recon pcap wigle/start /api/pineap/recon/newPOST new recon scan -
The Pager natively supports Evil WPA (rogue AP on
wlan0wpa: SSID, PSK, encryption WPA2-PSK / WPA3-SAE / WPA3-OAE, hidden, enabled) and Evil Enterprise (EAP, auth-pass capture), confirmed via the daemon binary strings and the native (virtual) pager menu. -
The daemon lacks routes for: connected clients (use
iwinfo), kick (hak5cmd PINEAPPLE_DEAUTH_CLIENT), nearby-AP scan (iwinfo scan), and handshake file listing (/root/loot/handshakes/). pager-webui already implements these.
Architecture
Backend (payload/user/general/pager-webui/server.py)
- Add a generic proxy handler
h_pineap_proxythat forwards the browser request (method + JSON body) verbatim to the daemon socket path/api/pineap/<subpath>using the existingdaemon_sock_call, and returns the daemon's JSON response. Register it for the whole native tree (get_config,set_config,hostapd/*,mimic/*,examine/*,ssidpool/*,ssidfilter/*,macfilter/*,interfaces/*,log/*,recon/new) so every native capability is reachable 1:1 through pager-webui's authenticated/api/pineap/*namespace. - Keep the custom endpoints that have no daemon route:
clients(iwinfo),clients/kick(deauth),aps(iwinfo scan),handshakes(loot listing + download/delete). - Add Enterprise data endpoints: list + clear of
hostap_basic/hostap_challengerows fromrecon.db(via the sqlite3 CLI, the same mechanism the recon page uses). - Delete the broken Mark VII-uci settings handlers (
SETTING_MAP,_uci_map,h_pineap_settings_get/post) and the filter handlers that returned hak5 usage text (h_filter_get/post); replace with the proxy. - On daemon socket failure return 502 with a JSON error; never crash.
Frontend (www/js/app.js, www/js/views.js, www/css/app.css)
-
Rail icon: change the PineAP rail item from
pineap(map-marker) to the existingwifiicon inicons.js/app.jsrail definition. -
Rebuild the PineAP page as 8 tabs matching the Mark VII structure (using the existing vanilla-JS SPA design language - material-style cards, toggles, tables, tab bar):
Tab Route Content PineAP #/pineapMode badge (Passive/Active/Advanced from pineap_disabled+mimic+evilwpa/enterprise), description, quick toggles (Capture SSIDs to Pool, Advertise AP Impersonation Pool, Randomize Source MAC), alert-payload info note, 4 status cards (Karma / Open Network / Evil WPA / Evil Enterprise) with Configure linksOpen AP #/pineap/openEnable PineAP (master), Karma, Logging group (handshakes/partial/pcap/wigle/recon), Capture SSIDs, Advertise Pool, Randomize MAC, AP Channel select, PineAP MAC + Target MAC (read-only) Evil WPA #/pineap/evilwpaSSID, passphrase, encryption select (WPA2-PSK / WPA3-SAE / WPA3-OAE), Hidden, Enabled; handshake capture card (Examine BSSID + start/stop/reset); captured handshakes table Enterprise #/pineap/enterpriseEnabled, Auth Pass Capture; Basic Data + Challenge Data tables with Clear Impersonation #/pineap/impersonationSSID pool textarea editor + Add + Clear; Advertise + Randomize toggles; pool start/stop/collect Clients #/pineap/clientsConnected clients table (MAC/interface/RSSI) + Kick, 5s auto-refresh Filtering #/pineap/filteringClient Filter + SSID Filter cards: Allow/Deny mode + line-based list textareas with add/delete/clear APs #/pineap/apsKept as-is (iwinfo scan table, 10s refresh) -
Mark VII-only controls with no Pager equivalent (Autostart, Beacon Responses, Beacon Intervals, enterprise cert generation) are omitted rather than greyed out; Client Connect/Disconnect Notifications are shown as an info note (the Pager handles these via alert payloads natively).
-
Register the new routes in the
routesmap and add the tab bar entries + CSS.
Data flow
Browser -> pager-webui /api/pineap/* (session-authenticated) ->
daemon_sock_call -> /tmp/api.sock -> Pager daemon -> pineapd/hostapd.
Mutating calls show a toast; failures surface a friendly error.
Error handling
- Daemon socket unavailable -> HTTP 502
{error}; frontend shows a toast and never renders a dead page. - Unknown/unsupported subpath -> 404 through pager-webui.
- Enterprise tables empty -> "no data" empty states (same pattern as Recon).
Testing
- Rewrite
tests/test_pineap_{settings,pool,clients,aps}.pyand addtest_pineap_evilwpa.py/test_pineap_enterprise.py/test_pineap_filtering.pyagainst the proxied shapes, mocking the daemon socket call (module-level monkeypatch per the existing test conventions). - Run the README's per-file unittest loop on Windows.
- On-device smoke test after
deploy.ps1: walk every tab, verify toggles persist across a reboot.
Out of scope
- Firmware changes; the daemon API internals are used as-is.
- A PR to
hak5/wifipineapplepager-payloads(packaging is drop-in ready).
Open items (resolved during implementation)
- Exact
hostapd/set_configEvil WPA field names (SSID/PSK/encryption/ hidden/enabled) - probe on the live device. Resolved: Evil WPA lives in UCIwireless.wlan0wpa. The daemon routePUT /api/settings/wifi/set_aptakes{"configs":[{interface, ssid, enctype, enabled, hidden, key, channel(int)}]}(full replace;channelmust be int).PUT /api/settings/wifi/get_apis a stub (always{"interfaces":[]}), so the webui reads UCIwireless.wlan0wpa/wlan0opendirectly.enctypevalues:psk2,psk,sae,none(notwpa2). Applying reconfigures the radio and briefly drops the management connection. ssidpoollist response shape (fallback:hak5cmd PINEAPPLE_SSID_POOL_LIST). Resolved:GET /api/pineap/ssidpool/listis a stub ({"success":true}); the pool is stored base64 in UCIpineapd.@ssidpool[0].ssid.hak5cmdPINEAPPLE_SSID_POOL_LIST/ADD/DELETE/CLEARall work and are used.- Randomize-Source-MAC route (
GetPineAPRandomizeMACinternal var) - discover the backing route/field. Resolved (partial): no readable daemon route for the pool advertise state (ssidpool/enable|disableare POST;enablereturns 500 natively because nowlan0openinterface exists on the Pager). The webui surfaces the daemon error. - sqlite3 CLI availability for the Enterprise tables.
Resolved: sqlite3 CLI present;
hostap_basic/hostap_challengedo not exist yet inrecon.db, so the Enterprise tab renders empty tables (webui returnsrows: []). - Pineapd UCI required-field cycle: the daemon's
set_config/hostapd/set_configare full-replaces. If a write omits required fields (pineapd.@pineapd[0]. reconpathetc.),get_configthen fails and later writes stay broken. The webui merges each write over the current daemon config (or defaults whenget_configfails) so required fields are always preserved. - Verified daemon methods: reads GET;
set_config/hostapd/set_config/hostapd/enable_pineap/interfaces/set_interface/ssidpool/add/wifi/*PUT; toggles (mimic/*,examine/*,ssidpool/enable|disable|enable_collect| disable_collect) POST.ssidfilter/macfilterset_configare PUT.