Retry and serialize pineapd/hak5 calls, queue virtual-pager keys, and grey out buttons until the pager finishes. Deploy now installs python3-light after factory firmware. Bump version to 1.3.2.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Env check is read-only when state is sane: no pineapd command-socket
writes, no live pool-list commits, no wifi reload; pineapd restarts only
when a runtime-sensitive UCI value changed or the daemon was down
- Failed monitor repairs now fail the startup contract instead of being
reported as fixed; runtime pool state is read from active config
- Enterprise AP recovery runs only on device boot (PAGER_WEBUI_BOOT), not
on every web-service restart
- serve() gates the HTTP port on startup checks with bounded retries and
shuts down cleanly on SIGTERM/SIGINT; the recon watchdog waits
interruptibly
- Recon uses a bounded userspace channel scheduler that drives both
monitor radios over non-DFS channels, with preflight verification,
serialized starts, and per-cycle error reporting
- payload.sh waits for real readiness on start, fully removes the boot
service (stop + disable + delete) on stop, and surfaces a
stopped-but-enabled boot service; deploy.sh refreshes the installed
init script even when the service is stopped
- Bump version to 1.3.1
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- STA uplink disable now uses uci commit + ip link set wlan0 down instead of
wifi reload, so the env check never bounces radios/APs/drops monitors
- Removed the wlan0mon 'hop is off' warning: field-verified hop=0 is normal
(wlan1mon also reports 0 while scanning both bands); the STA/AP pinning
checks are the real signals
- recon/status drops wlan0_hopping; UI keeps wlan0_sta + wlan0_pinned pills
The stock STA client interface (wlan0) holds phy0's channel, pinning wlan0mon
so 2.4GHz recon captures nothing (verified: iw set channel -> Resource busy
until wlan0 is down). env_check now disables it (uci wireless.dummy_radio0
disabled=1 + wifi reload) at startup and /api/recon/status exposes wlan0_sta
so the recon page can warn if it regresses.
The band UCI config looked correct but pineapd was not hopping wlan0mon at
runtime, so 2.4GHz recon results were entirely absent. env_check now parses
_pineap INTERFACE LIST and warns when wlan0mon hop is off; /api/recon/status
exposes wlan0_hopping and the recon scan bar surfaces it.
- env_check(): verifies daemon/pineapd/UCI/monitors/recon DB, auto-fixes
fixable issues and re-verifies; forces runtime SSID-pool broadcast off to
match the UI (kills the 'pool on but UI shows off' gap)
- server.py --env-check CLI; payload.sh runs it verbosely before starting,
aborts on core failure
- serve() runs the check at every startup (boot + procd respawn)
- /api/health exposes env report + pool_runtime; /api/recon/status exposes
wlan0_pinned (2.4GHz under-sampling warning); recon page warns when a
radio0 AP pins wlan0mon
- recon start failures now include the daemon reason in the UI error
- shared stabilization refactor (_stabilize_uci/PINEAPD_SAFE_UCI/_raise_monitors)
- tests: test_env_check.py (18) + health/recon updates
- Version 1.1 -> 1.2 in the hak5 manifest and MCP serverInfo.
- Removed leaked personal details from process docs: device root password,
the user's personal iPhone SSID (authorized-test target), the local
/Users/... checkout path, and the device IP where it appeared alongside
the password. Replaced with <device-password>, <authorized-test-ssid>,
<repo>, and <device-ip> placeholders.
- Landscape card mirrors Encryption: headline text removed; square 112px
ring (drawn height 112, CSS fixed square, no more ellipse) + HTML legend
(dot + label + count) for Access Points / Clients / Unassociated. The
canvas previously had no legend and the '90' headline never matched the
dominant arc; the legend makes every count visible and labeled.
- Legend markup generalized: .recon-enc-* -> .recon-chart-* shared by both
cards; shared chartLegendEntry() builder; landscape skips zero slices.
- .recon-toggle now flex-wraps (was overflowing 'Auto-collect handshakes'
past the card edge at narrow widths; card min-width inner is ~142px vs a
233px label).
Verified on device via CDP at 1200px and 860px viewports: landscape ring
112x112 square with Access Points 92 / Clients 291 / Unassociated 760;
encryption card intact; toggle label stays inside the 184px card (wraps to
2 lines, no card overflow); zero JS exceptions.
The enc canvas was drawn at 233x120 internally but .recon-chart-box canvas
forced width:100%/height:100% onto a ~233x115 box, scaling the bitmap and
flattening the ring. #recon-encryption is now a static 112px square with the
doughnut drawn at height 112, so internal and CSS pixels match (1:1) and the
circle stays circular. Verified on device: box and bitmap both 112x112,
card fits without overflow, legend intact, no JS exceptions.
- Ring and legend now derive from reconEncBucket's actual family keys
(WPA2-PSK, WPA3-Personal, WPA2-Enterprise, ...) instead of the six
nominal buckets that never matched encCounts, so the ring drew an
empty ring and the legend was always blank on WPA2-dominated data.
Ordering via RECON_ENC_ORDER; colors cycle RECON_ENC_COLORS.
- Legend div had class but no id while drawCharts looked it up with
getElementById — the population block silently never ran. Added the id.
Verified on device via CDP: legend lists Open 9, WEP 1, WPA2-PSK 44,
WPA3-Personal 20, WPA3-Enterprise 5 with per-family dot colors; no JS
exceptions.
A hung read can no longer stall the recon/pineap poll loops (AbortController).
Writes keep no client abort: radio deploys legitimately take up to 45s
server-side. Cache-bumped api.js.
The tool only accepted set_mode/add, so entries added via MCP could never be
removed. Now passes the full action set through to the same endpoint the UI
uses and returns the resulting mode/entries. Verified on device: add ->
delete round trip leaves the filter empty.
hak5cmd on this firmware has no CLIENT_KICK command and PINEAPPLE_DEAUTH_CLIENT
requires (bssid, target, channel) — the UI kick/deauth buttons and the MCP
pineap.kick_client tool previously passed only the client MAC, which printed
usage and silently did nothing.
- _deauth_target/_deauth_client_via_iface resolve the client's association
interface via iwinfo (Access Point + Channel), pick the band-aware inject
interface, and issue DEAUTH_CLIENT <bssid> <mac> <channel>
- h_client_kick: deny-filter (persistent) + immediate deauth with rc checks
- h_deauth_client: deauth with the full form; 502 with detail when the
client is not associated
- MCP pineap.kick_client: resolves the client first (no side effects on
failure), then deny-filter + deauth; verified on device (clean error for
unassociated clients, filter list restored)
- tests updated for the new command chain
- Top 5 recon cards restyled as stat cards: value + sub-line + mini chart,
consistent 190px anatomy; Handshakes links to the handshakes page;
Previous Scans shows count/latest plus a compact picker + action row
- Channel map records lobe geometry (canvas.__reconLobes / __reconLobesHit);
hovering lists the networks under the cursor, click pins the tooltip,
mouseleave hides it; empty states hide the tooltip too
- Recon focus sidebar gains 'Send to PineAP — Twin this network': routes to
Evil WPA (psk2/sae/owe from recon encryption) or OpenAP (with BSSID) and
prefills the form; one-shot PineAPPrefill is consumed by the attack
launcher and never auto-deploys or leaks into manual forms
- Existing Actions verified end-to-end and hardened: capture/stop handshake
sync the auto-collect toggle, examine buttons disable while pending
- Recon resilience: loadDetail retries after failed render or 503 (no more
permanently blank page), scan-list errors surface in the scan bar, poll
guard prevents overlapping loads, chart draws are individually isolated
- Auto-collect toggle re-syncs from get_config on the slow poll so the UI
tracks the pager's own settings