release: Mark VIII 1.0
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# Recon Mark VII Parity — Design Spec
|
||||
|
||||
- **Date:** 2026-08-11
|
||||
- **Status:** Approved
|
||||
- **Owner:** WiFi Pineapple Pager expansion project
|
||||
- **Applies to:** `payload/user/general/pager-webui/www/` (front-end) and
|
||||
`payload/user/general/pager-webui/server.py` (one backend change)
|
||||
|
||||
## 1. Goal
|
||||
|
||||
Rework the Pager WebUI Recon section so it looks and behaves as close as
|
||||
possible to the stock Hak5 WiFi Pineapple (Mark VII) UI's Recon at
|
||||
`http://172.16.42.1:1471/#/Recon`, using only data the Pager backend already
|
||||
exposes plus one small optional-body change to `POST /api/recon/start`.
|
||||
|
||||
Source of truth for the Mark VII layout: the Angular bundle
|
||||
`main.ce5a318adf590e170f6d.js` (captured 2026-08-11, cached at
|
||||
`%TEMP%\opencode\oldui_main.js`). The scanning component (`app-scanning-view`)
|
||||
template, component CSS, and Chart.js configs were extracted from it.
|
||||
|
||||
## 2. Mark VII Reference (extracted from bundle)
|
||||
|
||||
### Scanning page (`/Recon`, tab "Scanning")
|
||||
|
||||
```
|
||||
div.recon-title-card-container (flex, wrap, justify: space-between, gap 10px)
|
||||
div.recon-title-card-latest-overview
|
||||
mat-card (height: 200px)
|
||||
mat-card-title "Wireless Landscape" (font-size 20px)
|
||||
mat-card-content > div > div.recon-wifidata-chart-container
|
||||
canvas#landscapeChart (doughnut)
|
||||
div.recon-center-text > span.recon-no-data " No wireless landscape data is available yet. "
|
||||
div.recon-title-card-latest-overview "Channel Distribution" → canvas#channelChart (bar)
|
||||
div.recon-title-card-latest-overview
|
||||
mat-card (height: 200px)
|
||||
mat-card-title > a.recon-card-title-link [routerLink /Recon/handshakes] " Handshakes "
|
||||
content: <span font-size:32px><b>{totalHandshakes}</b></span>
|
||||
<span color:grey>Handshakes Captured</span>
|
||||
<mat-slide-toggle>Automatically Collect Any Handshakes</mat-slide-toggle>
|
||||
div.recon-title-card-latest-overview
|
||||
mat-card (height: 200px)
|
||||
mat-card-title "Previous Scans"
|
||||
content: mat-form-field (width 100%) > mat-label "Previous Scan" + mat-select
|
||||
button[mat-icon-button] mat-icon "file_download"
|
||||
button[mat-icon-button] mat-icon "delete"
|
||||
|
||||
mat-card (scan bar)
|
||||
mat-card-content > div (height 48px, flex align-center)
|
||||
mat-slide-toggle "Scan" (reconToggleState → startRecon/stopRecon)
|
||||
div (margin-left 20px) mat-select (width 100px) scan_time
|
||||
options: 30 Seconds/1 Minute/2 Minutes/5 Minutes/10 Minutes/Continuous
|
||||
div (margin-left 20px) mat-select band (0 = 2.4GHz, 1 = 5GHz, 2 = 5GHz-DFS)
|
||||
span[fxFlex] spacer
|
||||
button[mat-icon-button] mat-icon "settings" (opens settings sidebar)
|
||||
|
||||
div (position: relative; min-height: 500px)
|
||||
div.recon-scan-results-card
|
||||
mat-card
|
||||
mat-card-content
|
||||
div (48px row) [AP table header: search mat-form-field "Search" + mat-paginator]
|
||||
mat-table APs columns: SSID, MAC, Clients, OUI, Sec, WPS, MFP, Chan, Sign, FirstSeen, LastSeen
|
||||
mat-card-content [Clients table: search + mat-paginator]
|
||||
mat-table Clients columns: Client MAC, Signal, Channel, First seen, Last seen
|
||||
```
|
||||
|
||||
Charts (from `generateLandscapeChart` / `generateChannelChart`):
|
||||
- Landscape: `type:"doughnut"`, labels `["Access Points","Clients","Unassociated"]`,
|
||||
backgroundColor `["#2ecc71","#2980b9","#8e44ad","#e74c3c"]`, `legend:{position:"bottom"}`.
|
||||
- Channel: `type:"bar"`, one bar per channel sorted ascending, no legend, each bar
|
||||
a color from a 64-color array, `yAxes:[{ticks:{reverse:!1,stepSize:1,min:0}}]`.
|
||||
|
||||
Component CSS (key rules, light theme):
|
||||
- `.recon-title-card-container{display:flex;width:100%;flex-wrap:wrap;justify-content:space-between}`
|
||||
- `.recon-title-card-latest-overview{flex:1;margin-bottom:1em}`
|
||||
- `.recon-title-card-title{font-size:20px;margin-bottom:15px;display:flex;align-items:center}`
|
||||
- `.recon-card-title-link{color:inherit;text-decoration:none}` `:hover{text-decoration:underline}`
|
||||
- `.recon-title-card-content{display:flex;justify-content:center;align-items:center;height:70%}`
|
||||
- `.recon-no-data{font-style:italic;color:#787878;display:flex;justify-content:center}`
|
||||
- `.recon-scan-results-card{width:100%}`
|
||||
- table rows cursor pointer; `.recon-table-row-active{background-color:#eaeaea}`
|
||||
- dark: `.recon-table-row-active-dark{background-color:#565656}`
|
||||
|
||||
Tabs: Recon has exactly two tabs — `[Scanning → /Recon]`, `[Handshakes → /Recon/handshakes]`. No Events tab.
|
||||
|
||||
### Handshakes page (`/Recon/handshakes`)
|
||||
Card "Captured WPA Handshakes" (title flex, settings icon button at right),
|
||||
`table-container` with `mat-table`: columns `BSSID, Client, Source, Type, Captured,
|
||||
Message 1, Message 2, Message 3, Message 4, Beacon Frame, [action]`. Rows show
|
||||
M1–M4 check/close/missing glyphs. Delete + download per row.
|
||||
|
||||
## 3. Design (Pager)
|
||||
|
||||
### 3.1 Tabs
|
||||
`RECON_TABS` becomes two entries: **Scanning** (`#/recon`) and **Handshakes**
|
||||
(`#/recon/handshakes`). Remove `views.recon_events`, the `#/recon/events`
|
||||
route in `app.js`, and the old `views.recon_events` definition. Backend
|
||||
`GET /api/recon/events` is left untouched.
|
||||
|
||||
### 3.2 Scanning view layout (`views.recon`)
|
||||
Mark VII structure implemented with vanilla JS `h()` helpers and existing
|
||||
`PagerAPI` endpoints. State per scan: `GET /api/recon/scans` → list;
|
||||
`GET /api/recon/scans/{id}` → detail `{scan, aps[], clients[], handshakes[]}`.
|
||||
|
||||
- **Title cards row** (`.recon-title-card-container`, 200px cards):
|
||||
1. **Wireless Landscape** — `MiniChart.doughnut` with legend; segments
|
||||
`[Access Points, Clients, Unassociated]` = `[aps.length, clients.length, 0]`,
|
||||
colors `#2ecc71 / #2980b9 / #8e44ad`; placeholder text when no data.
|
||||
2. **Channel Distribution** — `MiniChart.bar`; per-channel counts from
|
||||
detail APs (unknown channel grouped as `?`), Mark VII 64-color palette,
|
||||
no legend, Y step 1.
|
||||
3. **Handshakes Captured** — 32px bold count = selected scan handshakes
|
||||
length; grey "Handshakes Captured" subtitle; "Automatically Collect Any
|
||||
Handshakes" slide toggle wired to `GET/POST /api/pineap/settings`
|
||||
(`collect_handshakes`); card title links to `#/recon/handshakes`.
|
||||
4. **Previous Scans** — "Previous Scan" select (newest first, `Scan #id — time`
|
||||
labels), `file_download` icon button → existing
|
||||
`/api/recon/scans/{id}/download/json`, `delete` icon button → existing
|
||||
`DELETE /api/recon/scans/{id}` (confirm dialog), refresh via poll.
|
||||
- **Scan bar card** (48px row): "Scan" slide toggle (`POST /api/recon/start|stop`),
|
||||
Duration select (30 Seconds / 1 Min / 2 Min / 5 Min / 10 Min / Continuous),
|
||||
spacer, `settings` icon button → settings sidebar. No Band select (Pager
|
||||
cannot single-band scan). Duration persisted in `localStorage`
|
||||
(`pw_scan_duration`) and sent on start.
|
||||
- **Results area** (`min-height:500px`), one card per table, each with a
|
||||
Material-look "Search" field (client-side filter) and a paginator
|
||||
(10/25/50/100, first/last/prev/next buttons, "1–10 of N" range label):
|
||||
- **Access Points** — columns SSID, BSSID, Channel, Signal, Encryption,
|
||||
Hidden; row click selects the AP (highlight) — no focus sidebar (backend
|
||||
has no scan-AP deauth/capture APIs).
|
||||
- **Clients** — columns MAC, Signal, Frequency, Packets.
|
||||
- **Settings sidebar**: fixed right panel (top 64px, width 270px, shadow,
|
||||
close button). Section "Access Points": Show SSID/MAC/Channel/Signal/
|
||||
Encryption/Hidden toggles. Section "Clients": Show MAC/Signal/Frequency/
|
||||
Packets toggles. Persisted as JSON in `localStorage` key `pw_recon_cols`.
|
||||
- **Polling**: refresh scans/detail every 10s while the view is mounted
|
||||
(destroy clears interval), same as today's behaviour (interval bumped from
|
||||
15s → 10s to keep charts/table fresh).
|
||||
|
||||
### 3.3 Handshakes view (`views.recon_handshakes`)
|
||||
Restyle to Mark VII look: card title "Captured WPA Handshakes" with a
|
||||
`settings` icon button (non-functional on Pager; omitted or rendered as a
|
||||
disabled hint — render it, clicking shows a toast "Settings not available on
|
||||
Pager"). Table `File / Type / Size / Modified` plus per-row `Download` and
|
||||
`Delete` actions (existing `/api/pineap/handshakes` endpoints + `/api/loot/zip`
|
||||
for "Download all"). Keep existing zip/archive actions row.
|
||||
|
||||
### 3.4 Charts (`js/chart.js`)
|
||||
- `MiniChart.doughnut(canvas, segments, { legend: true, height })` — redraw as
|
||||
a true doughnut (inner hole via `arc` ring) and draw a legend row beneath
|
||||
(color dot + label) when `legend` is set.
|
||||
- `MiniChart.bar(canvas, items, opts)` — items `{label, value, color}`; draws
|
||||
Y gridlines, bars from baseline, X labels, `maxY = ceil(max/1)`; Mark VII
|
||||
palette cycles through `items[].color`.
|
||||
- Keep existing `MiniChart.draw` (line) for the dashboard unchanged.
|
||||
|
||||
### 3.5 Icons (`js/icons.js`)
|
||||
Add to `PineappleIcons`: `refresh`, `file_download`, `delete`, `settings`,
|
||||
`search`, `first_page`, `last_page`, `chevron_left`, `chevron_right`
|
||||
(Material Design path data; `wifi`/`extension`/`receipt` already present).
|
||||
|
||||
### 3.6 CSS (`css/app.css`)
|
||||
Add Mark VII recon styles (light + `html.dark`): `.recon-title-card-container`,
|
||||
`.recon-title-card`, `.recon-title-card-title`, `.recon-card-title-link`,
|
||||
`.recon-title-card-content`, `.recon-no-data`, `.recon-chart-box`,
|
||||
`.recon-scan-bar`, `.recon-scan-bar .sel`, `.recon-search`,
|
||||
`.recon-paginator`, `.recon-settings-sidebar`, `.recon-settings-section`,
|
||||
`.recon-settings-toggle`, `.recon-settings-close`, `.recon-row-selected`.
|
||||
Card background follows `--surface`; title cards get the existing elevation
|
||||
shadow; dark overrides via `html.dark`.
|
||||
|
||||
### 3.7 Backend (`server.py`)
|
||||
`h_recon_start(ctx)` forwards an optional `scan_time` from the request body to
|
||||
the daemon:
|
||||
|
||||
```python
|
||||
def h_recon_start(ctx):
|
||||
body = {}
|
||||
scan_time = (getattr(ctx, 'body', None) or {}).get('scan_time')
|
||||
if scan_time is not None:
|
||||
body['scan_time'] = int(scan_time)
|
||||
status, data = daemon_sock_call('POST', '/api/pineap/log/recon/start', body=body)
|
||||
...
|
||||
```
|
||||
|
||||
Default remains `{}` when no `scan_time` is sent, so the current behaviour is
|
||||
unchanged. (Whether the Pager daemon honours `scan_time` is up to the daemon;
|
||||
the UI persists and sends it either way.)
|
||||
|
||||
### 3.8 Routing (`js/app.js`)
|
||||
Remove `'#/recon/events': 'recon_events'` from the `routes` map. No other
|
||||
route changes.
|
||||
|
||||
## 4. Data flow
|
||||
Unchanged API surface (except optional `scan_time` on recon start). The view
|
||||
loads scans, auto-selects the newest, fetches the detail, renders charts +
|
||||
tables, and re-fetches on a 10s interval. Search/pagination/column settings
|
||||
are client-side state (`localStorage` keys `pw_scan_duration`, `pw_recon_cols`).
|
||||
|
||||
## 5. Testing
|
||||
- Python: extend `tests/test_recon.py` `DaemonSockTest` with a case asserting
|
||||
`h_recon_start` forwards `{'scan_time': 60}` when present and `{}` otherwise
|
||||
(existing socket tests must stay green).
|
||||
- Front-end: manual on-device smoke pass — every element of the scanning page,
|
||||
tabs (2), scan start/stop, duration persistence, auto-handshake toggle,
|
||||
previous-scan select + download + delete, table search/pagination, column
|
||||
settings sidebar + persistence, handshakes page, dark theme, keyboard
|
||||
shortcut `r`.
|
||||
- Deploy via `scripts/deploy.ps1`; `curl` the served JS/CSS assets for 200.
|
||||
|
||||
## 6. Out of scope
|
||||
- AP/client "focus" sidebars (deauth/capture/clone) — no backend support.
|
||||
- 2D/3D cartography graph view — no AP↔client association data.
|
||||
- Chart.js dependency — hand-rolled canvas rendering with identical palettes.
|
||||
- Events tab, band select, "highlight active devices" aux settings.
|
||||
- Backend removal of `/api/recon/events`.
|
||||
Reference in New Issue
Block a user