Adds a new default plugin that provides a web UI for browsing,
downloading, and analyzing captured WiFi handshakes and network data.
Features:
- Browse and search captured .pcap handshake files
- Download individual files or all as a zip archive
- Interactive network map with D3.js force-directed graph
- Zoom, pan, drag nodes to rearrange
- AP nodes colored by encryption type, sized by client count
- Click AP to highlight its connected clients
- Auto-fits to viewport after layout settles
- Sortable table view with expandable AP rows showing clients
- Handshake column with download links for captured .pcap files
- Historical AP import from existing pcap filenames
- Live data from bettercap session merged with persistent history
- Stats bar: AP count, unique clients, total data volume
- Persistent JSON storage surviving reboots
Add _IFACE_RE regex and _validate_iface() classmethod that validates
Linux network interface names (max 15 chars, alphanumeric plus dash
and underscore). Provides a safety net against malformed names if
interface configuration is ever externalized.
on_epoch and on_bcap_sys_log run from different threads (main loop vs
bettercap event handler). Both read and write self.LASTTRY without
synchronization, creating a race where two recovery actions fire
simultaneously. Similarly, isReloadingMon can be checked and set by
concurrent threads leading to overlapping restarts.
Add a threading.Lock to serialize cooldown checks and state mutations:
- on_bcap_sys_log: lock around LASTTRY cooldown check
- on_epoch: lock around LASTTRY cooldown check
- _tryTurningItOffAndOnAgain: lock around duplicate-attempt guard,
early return instead of else-block to flatten indentation
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Patterns 5 (concurrent map iteration) and 6 (panic: runtime error) had
identical handlers — both log "Bettercap has crashed!", restart bettercap,
and restart pwnagotchi. Merge into a single elif with an or condition.
Closes#539
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Plugin code uses print() in several places instead of the logging
module. On a headless Pi Zero, print() output goes nowhere useful
while logging integrates with pwnagotchi's log system.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
'"success" in result' checks if the key exists in the dict (always
True for valid responses), not whether the operation succeeded.
result["success"] can KeyError if the key is missing.
Change all checks to result.get("success") which correctly returns
the boolean value or None if the key is absent.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_epoch calls agent.view() directly without checking hasattr first,
unlike every other method in the plugin. This crashes if the agent
has no view attribute (e.g., during early startup or in headless mode).
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_ui_setup computes a pos variable from options or defaults but
never uses it. The ui._lock context and logging.debug("Got here")
are leftover scaffolding with no effect.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_ready opens a subprocess.Popen to read journalctl but never uses
the result. The Popen object is never closed, leaking a file descriptor
and zombie process on every startup.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Typo "wifi.interfaceface" should be "wifi.interface" in the debug
log for the bettercap set wifi.interface command result.
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
Four robustness improvements to PiSugarServer I2C communication:
1. Race condition: build i2creg into temp list, swap atomically with
threading lock so UI thread never reads partial register data.
2. Bus recovery: add error counter with exponential backoff (3s-30s),
log suppression after 3 errors, and SMBus reconnect after 5
consecutive failures to recover from MCU deep sleep.
3. Write protection: restructure as try/finally so register 0x0B is
always re-enabled even if the middle write fails.
4. Shutdown safety: wrap I2C writes in try/except/finally so failures
are logged but never prevent pwnagotchi.shutdown() from executing.
Fixes#511
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
For PiSugar2/2Plus with max_charge_voltage_protection enabled,
battery_voltage was appended to voltage_history twice per cycle:
once inside the charge protection block and once unconditionally
at the end. This skews the trimmed-mean battery level calculation.
Make the final append conditional so each model appends exactly
once per cycle regardless of charge protection setting.
Fixes#509
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
on_loaded crashes with AttributeError when PiSugar is not connected
because it accesses self.ps without a None check. Also uses direct
dict access on self.options which crashes if keys are missing.
on_ui_update crashes when checking battery_plugged outside the
self.ready guard, hitting self.ps.get_battery_power_plugged on None.
Changes:
- Wrap self.ps access in on_loaded with None guard
- Use self.options.get() with safe defaults
- Move battery_plugged inside self.ready + self.ps check
- Downgrade "PiSugar is not ready" from info to debug
Fixes#507
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>
The web UI checks for 'Pisugar 3' (with space, lowercase 's') but
the model detection sets self.model = 'PiSugar3' (no space, uppercase 'S').
This causes 5 PiSugar3-specific fields to never display their actual values.
Replace all occurrences to match the value set during initialization.
Fixes#505
Signed-off-by: PwnPacker <4704376+CoderFX@users.noreply.github.com>