Files
Mark-VIII/docs/superpowers/specs/2026-08-11-openap-mk7-card-design.md
T
2026-08-11 20:24:24 -07:00

87 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Mk7 "PineAP Open Access Point" Card — Design
**Goal:** Rebuild the Open AP tab (`#/pineap/open`, `views.pineap_open`) to visually and functionally match the genuine Mark 7 Pineapple's `/PineAP/open` page: a single **"PineAP Open Access Point"** card with Open AP network settings and filter notices. The current grouped-toggles "PineAP settings" card is removed.
**Reference:** Verified against the real Mk7 firmware bundle served at `http://172.16.42.1:1471/` (`main.ce5a318adf590e170f6d.js`), component `app-open-wifi-view` (selector), template root `QAt`.
## 1. Frontend — `views.pineap_open`
Rendered inside `pineapShell(root, '#/pineap/open')`. A single `.pineap-title-card` (matching the clone's existing Mk7 card styling) containing, top to bottom:
- **Title:** "PineAP Open Access Point" (`.pineap-card-title`).
- **Subtitle:** "The Open SSID is advertised without encryption. When client association is enabled, " followed by a filter-dependent sentence selected by the SSID/client filter modes:
- ssid=allow ∧ client=allow → "any client in the filter configuration may connect to any SSID in the filter configuration."
- ssid=deny ∧ client=allow → "any client not in the filter configuration may connect to any SSID in the filter configuration."
- ssid=allow ∧ client=deny → "any client in the filter configuration may connect to any SSID not in the filter configuration."
- ssid=deny ∧ client=deny → "any client not in the filter configuration may connect to any SSID not in the filter configuration."
- ("filter configuration" links to `#/pineap/filtering`.)
- **Fields** (two `.row`s; labels above inputs per the clone's `label { display:block }` style):
1. **Open SSID** — text input.
2. **BSSID** — text input.
3. **Channel**`<select>` of channels 111, values `1`..`11`.
4. **Current Country**`<select>` of the Mk7 82-entry country list (see §3).
- **Switches** (existing `.switch` slider CSS):
- **Hidden** — bound to the Open AP `hidden` state.
- **Respond to all probe requests (impersonate all networks)** — bound to the PineAP `karma` state (the Mk7 binds this exact toggle to `PineAPSettings.karma`). The daemon exposes no readable karma/mimic state (verified: `get_config` has no `mimic`), so the toggle is **session-tracked** (module-level flag, default off, updated on Save) — consistent with the Overview's `karmaOn` handling. Save still POSTs `mimic`.
- **Info line** (below the switches, small muted text): "The Open access point will be " + ("hidden" if hidden else "advertised") + "." plus, when karma is on, the filter sentence from the subtitle's logic. The Mk7's ", and SSIDs from the Spoofed SSID Pool will be advertised" clause is **omitted**: the daemon exposes no readable broadcast/advertise state (pre-existing limitation; the Overview's advertise toggle has the same issue).
- **Filter notice boxes** (stacked, below the info line), mirroring the Mk7's infobox conditions and actions:
1. If SSID filter fetched ∧ Open SSID not in SSID-filter allow list ∧ mode=allow → error box: `The open SSID "<ssid>" is not included in the filter allow list, clients will not be able to connect.` + **Add Allowed** button → `POST /api/pineap/filters/ssid {action:'add', value: ssid}` then reload.
2. If SSID filter fetched ∧ Open SSID in SSID-filter list ∧ mode=deny → box: open SSID is blocked by the filter deny list + **Remove Filter** button → `POST /api/pineap/filters/ssid {action:'delete', value: ssid}` then reload.
3. If mode=allow ∧ SSID filter list non-empty ∧ karma → info box: "Remember to add SSIDs you wish to impersonate to the PineAP SSID filter (Deny)." + **Change Filters** link → `#/pineap/filtering`.
4. If client filter fetched ∧ client mode=allow ∧ client list empty → error box: "The PineAP Client filter is set to allow mode. When using this mode, " + the mode-dependent sentence + **Change Mode** button (→ `POST /api/pineap/filters/client {action:'set_mode', mode:'deny'}`, then reload) + **Change Filters** link.
- **Save button** (`.btn`) + muted note "Applying reconfigures the radio — you may be disconnected briefly."
- Save payload: `POST /api/pineap/wifi/set_ap` with `{open: {ssid, bssid, hidden, enabled, channel, country}}` where `enabled` is the value loaded from `get_ap` (preserved; the Mk7 card has no Enabled control), plus `POST /api/pineap/mimic {enable: <karma switch>}`. All via `Promise.allSettled`.
- Feedback via `App.toast('Open AP saved')` / `App.toast(..., 'error')`.
**Old card removed:** the "PineAP" grouped settings card (Enable PineAP / Karma / Capture SSIDs / Advertise / Logging toggles + footer MAC line + batched `saveCfg`) is deleted. Enable PineAP and Karma are covered by the Overview mode bar; SSID-pool capture/advertise by Overview Quick Settings; logging by Evil WPA / Logging. Nothing else in the app references the removed code.
## 2. Backend — `server.py`
Extend the two existing handlers; no new routes, no daemon changes.
### `h_pineap_wifi_get_ap` (currently ~line 1479)
The `open` object gains fields; reads remain UCI-based (`_uci_wifi_iface('wlan0open')`, radio config via `_uci_wifi_iface('radio0')` or equivalent):
- `ssid``open_cfg.get('ssid') or ''`.
- `bssid`**`open_cfg.get('macaddr') or ''`** (the Open AP interface MAC; changed from the ssidpool bssid). Verified: the only consumer of `open.bssid` is the old Open tab footer, which is being removed; the Overview uses only `open.enabled`.
- `hidden``open_cfg.get('hidden') == '1'`.
- `channel` — radio0 channel (2.4GHz radio hosting the open AP), as int if numeric, else `None`.
- `country` — radio0 country code or `''`.
- `enabled`, `target` unchanged (`enabled` = `open_cfg.get('disabled') == '0'`; `target` = pool target).
### `h_pineap_wifi_set_ap` (currently ~line 1505)
The `open` branch gains support:
- Pass `bssid` (→ `macaddr`), `hidden`, `channel` through to the daemon `PUT /api/settings/wifi/set_ap` open config (the daemon persists these to `wireless.wlan0open`, verified on-device: it writes `macaddr`, `hidden`, `channel`, `encryption`).
- **Country** and **radio channel** are applied directly: if `open.country` present, `uci set wireless.radio0.country=<code>`; if `open.channel` present, `uci set wireless.radio0.channel=<n>`; then `uci commit wireless` + `wifi reload`. (The daemon's iface-level channel write is inert for the actual radio — verified.) Only write/reload when the value changed.
- `enabled` semantics unchanged (preserve existing state when not supplied).
### Karma
"Respond to all probe requests" is saved by the frontend via the existing `POST /api/pineap/mimic {enable}`; no backend change.
## 3. Data lists (frontend constants)
- **Channels (2.4GHz):** 1..11 (labels "Channel N (24NN MHz)" matching Mk7; values 1..11).
- **Countries:** the Mk7's 82-entry list (US United States, DZ Algeria, AR Argentina, AU Australia, AT Austria, BH Bahrain, BM Bermuda, BO Bolivia, BR Brazil, BG Bulgaria, CA Canada, CL Chile, CN China, CO Colombia, CR Costa Rica, CS Cyprus, CZ Czech Republic, DK Denmark, DO Dominican Republic, EC Ecuador, EG Egypt, SV El Salvador, EE Estonia, FI Finland, FR France, DE Germany, GR Greece, GT Guatemala, HN Honduras, HK Hong Kong, IS Iceland, IN India, ID Indonesia, IE Ireland, PK Islamic Republic of Pakistan, IL Israel, IT Italy, JM Jamaica, JO Jordan, KE Kenya, KW Kuwait, LB Lebanon, LI Liechtenstein, LT Lithuania, LU Luxembourg, MU Mauritius, MX Mexico, MA Morocco, NL Netherlands, NZ New Zealand, NO Norway, OM Oman, PA Panama, PE Peru, PH Philippines, PL Poland, PT Portuagal, PR Puerto Rico, QA Qatar, KR Republic of Korea (South Korea), RO Romania, RU Russia, SA Saudi Arabia, SG Singapore, SI Slovenia, SK Slovak Republic, ZA South Africa, ES Spain, LK Sri Lanka, SE Sweden, CH Switzerland, TW Taiwan, TH Thailand, TT Trinidad and Tobago, TN Tunisia, TR Turkey, UA Ukraine, AE United Arab Emirates, GB United Kingdom, UY Uraguay, VE Venezuela, VN Vietnam).
## 4. Filter state data (frontend)
- SSID filter: `GET /api/pineap/filters/ssid``{mode, entries}` (existing handler). Mode `allow`/`deny`.
- Client filter: `GET /api/pineap/filters/client``{mode, entries}`.
- Mutations use the existing `action`-based API (matching `views.pineap_filtering`):
- Add Allowed / Remove Filter: `POST /api/pineap/filters/ssid` with `{action:'add'|'delete', value: ssid}`.
- Change Mode: `POST /api/pineap/filters/client` with `{action:'set_mode', mode:'deny'}`.
## 5. Error handling & UX
- All load fetches use `.catch(() => ({ data: {} }))` (existing pattern); the card still renders with empty fields if a fetch fails.
- Save = `Promise.allSettled([set_ap, mimic])`; toast "Open AP saved" only if all fulfilled, else "Some settings failed" (error); always re-run `load()`.
- Add Allowed / Remove Filter / Change Mode: fire, toast, re-run `load()`; failures toast 'Failed' (existing pattern).
## 6. Testing
- **Backend unit tests** (`tests/test_pineap_proxy.py`): extend the existing mocked-UCI tests —
- `test_wifi_get_ap_reads_uci_wireless`: mock `uci show wireless.wlan0open` with `ssid`/`macaddr`/`hidden`, and `uci show wireless.radio0` with `channel`/`country`; assert the new `open` fields.
- `test_wifi_set_ap_builds_configs`: open config now carries `bssid`/`channel`; country write triggers `uci set wireless.radio0.country` (mock `device_run`, assert the `uci set` + `uci commit` + `wifi reload` calls) only when country changed.
- Full unittest loop stays green.
- **JS:** delimiter-balance checker (`C:\Users\root\AppData\Local\Temp\opencode\js_balance.py`); no node available.
- **Deploy + on-device:** deploy via `scripts/deploy.ps1`; restart webui; curl save-path round-trip: set Open SSID/hidden via `wifi/set_ap`, verify `uci show wireless.wlan0open`, restore original values. Visual check against `http://172.16.42.1:1471/#/PineAP/open`.