Fixes found running WIFICANARY on a WiFi satellite node that pushes its
detections to a hub with no WiFi of its own.
Synced plugin objects were stored with syncHubNodeName = "decoded"
instead of the node's name. plugin.py took filename.split(".")[2], but by
the time the hub processes the file decode_and_rename_files() has renamed
it to last_result.<PREFIX>.decoded.<NodeName>.<N>.log, so index 2 is the
literal marker. The parsing now lives in
utils.plugin_utils.get_sync_hub_node_name(), next to the function that
produces these names; it keeps node names that contain dots and returns
"" for local result files.
WIFICANARY's absent_baseline_clone was evaluated per trusted_aps entry,
so with a main AP + range extender pair, a weak clone seen while only the
main AP was in range also raised absent_baseline_clone through the
extender's entry, on top of the correct evil_twin. The baseline now
counts as present if any trusted radio for that SSID is visible;
single-entry behaviour is unchanged.
Leaving WIFICANARY_IFACE blank is how such a hub ingests the node's
detections (core processes the synced files after the plugin runs), but
it logged an unconditional "not set - nothing to scan" every cycle. It is
now a verbose "hub-only mode" message, and the node + hub setup is
documented in the setting description and the plugin README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PzCQWQVz9b2UzqLiGp2mPM
The SSE endpoint event advertised the absolute path /mcp/messages, which drops the /server prefix when clients connect through the bundled nginx proxy on port 20211. Clients then POST to /mcp/messages, nginx serves it as a static file and returns 404, so MCP clients can't connect via the proxy. A relative path resolves against whichever SSE URL the client used, so it works both directly and behind the prefix.
check_trusted_aps() evaluated a rogue AP once per trusted_aps entry sharing
its SSID, so the documented main-AP+extender pattern (same SSID, two
entries) produced duplicate (bssid, motor) rows for a real clone - a
problem once next_release's per-plugin identity-hash dedup guard lands in
main, since it drops a plugin's entire batch on any internal duplicate.
Fixed by deduping once in main() after collecting from all check_*
functions. Also added iw + its setcap to Dockerfile.debian and
.devcontainer/Dockerfile, which the original PR missed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011meLPKCzVpdZyAUfv5U6mm
- check_trusted_aps() was evaluating every AP sharing a protected SSID
against every trusted entry for that SSID, not just its own. A main AP
requiring a stricter accepted security set (e.g. wpa3-only) than a
separately-trusted extender (e.g. wpa2) caused the extender to be
flagged as evil_twin/absent_baseline_clone - it was being judged
against the main AP's accepted set instead of its own. Fixed by
excluding, from each trusted entry's evaluation, any BSSID that has its
own separate trusted entry for the same SSID.
- README's "iw isn't in the published image yet" section was already
stale within the same PR - this branch's own Dockerfile change adds
iw + setcap, so the image ships it. Replaced with one sentence.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>