Commit Graph

117 Commits

Author SHA1 Message Date
Vashiru 667169c7ff feat: Bump to 168 hours to match docs.meshcore.io 2026-07-08 10:12:47 +01:00
Vashiru 17f8bcca2f feat: Allow setting max. flood interval to 50 2026-07-08 10:12:46 +01:00
agessaman 4a055be8df fix(router): try both companion and server on colliding dest hash
On-air dest hashes are one byte, so a companion and a room-server (or
repeater) identity can share one. The login and text dispatch used
`if dest_hash in companion_bridges: ... elif login_helper/text_helper`,
so a companion silently shadowed a same-hash room server: its login
never reached the room-server handler and failed with Invalid HMAC
(e.g. Lake Stevens pubkey f55d.. / hash 0xf5 colliding with a companion).

Offer the packet to both handlers when both are registered at the hash;
decryption disambiguates — the key owner replies, the other fails HMAC
and no-ops. Non-colliding paths are unchanged. Applied to both the
LoginServerHandler and TextMessageHandler branches.

Adds regression tests covering collision (both invoked), companion-only
(server helper skipped), and server-without-companion for each path.
2026-07-07 14:51:59 -07:00
agessaman 954150b2d8 merge: reconcile companion cleanup with fix-general-tidy
Merge the maintainer's fix-general-tidy branch (neighbor discovery,
keygen, API endpoints, web-asset rebuild, HTTP server config/control
commands, and an independent #286 room-server push/ACK/guest fix) into
the companion cleanup branch.

Both branches fixed #286 in parallel with byte-identical push-ACK CRC
logic. In the six overlapping files the maintainer's implementation is
kept (ACL replay-detection/session helpers, encoded path-len with legacy
fallback, expected_crc/ack_timeout_s injector API, dispatcher ACK
helpers); this branch's unique companion work is preserved on top
(sender_prefix persistence + migration, boot-state hardening /
CompanionStateLoadError, MessageQueue.max_size, older-core fallbacks).

Conflict resolution took the maintainer's side across the overlap, then
fixed two integration seams the merge introduced and updated this
branch's tests to the maintainer's API:
- room_server: timeout used undefined `hops`; aligned to `path_len`.
- packet_router: PATH helper was invoked twice (maintainer's
  unconditional call plus this branch's conditional local-identity
  call); dropped the now-redundant conditional block.

Pin openhop_core to @dev (was @feature/publish-workflow-message-handling)
so this can merge to the repeater's dev; core dev carries the required
sender_prefix and PathUtils.is_valid_path_len APIs.

Full suite green (1040 passed) against openhop_core dev and
refactor/companion-housekeeping; ruff clean.
2026-07-07 12:56:43 -07:00
agessaman b2e45c2038 fix: resolve room-server push ACKs through the dispatcher
Room server pushes waited on dispatcher.wait_for_ack, but nothing in the
repeater could ever resolve it, so every push timed out and re-pushed on
the backoff schedule (issue #286's duplicate floods — worst for virtual
companions on the same instance, whose ACKs never even cross the air):

- no core AckHandler is registered (all RX lands in the router fallback),
  so received ACK CRCs were never fed to dispatcher ACK matching
- inject_packet waited on packet.get_crc(), a packet-hash CRC that no ACK
  sender produces; the crypto CRC only the room server knows was ignored
- PATH returns (how a flood-received DM is ACKed) were decrypted by
  PathHelper, but it read the encoded path_len wire byte as a raw count —
  an empty 3-byte-hash path (0x80) parsed as a 128-byte truncated
  payload — and the router's PATH branch never ran PathHelper for
  room/repeater destinations when any companion bridge existed

Fixes:
- router ACK branch feeds discrete ACK CRCs (RF and locally injected) to
  dispatcher._register_ack_received
- PATH packets addressed to a local server identity are processed by
  PathHelper regardless of companion bridges; PathHelper decodes the
  encoded path_len via PathUtils, keeps the encoded byte in out_path_len,
  and registers the embedded ACK via ack_received_fn
- inject_packet accepts expected_ack_crc/ack_timeout; the room server
  passes its crypto CRC and a hop-count-based timeout (the encoded byte
  would have produced a ~4-minute direct-push wait)

Verified live on a real mesh: push to a same-instance virtual companion
resolves via the PATH-embedded ACK (encoded path_len 0x80) and push to a
firmware client resolves via the discrete RF ACK, no re-push loops.

Fixes #286
Fixes #341
2026-07-07 11:17:54 -07:00
agessaman 9c6ea0151e fix: compute signed-post push ACK over the full signed span
push_post_to_client sent posts as TXT_TYPE_SIGNED_PLAIN (plaintext =
timestamp + flags + author_prefix + text) but computed its expected ACK
over the plain-DM span (timestamp + attempt byte + text). Signed-plain
receivers (firmware BaseChatMesh::onPeerDataRecv, and openhop_core's
text handler since it gained signed-message ACKs) reply with
sha256(decrypted[0 : 9 + strlen(text)] || client_pubkey)[:4], so the
server never recognized any push ACK: every push timed out and the same
posts were re-pushed forever (issue #286's repeating 'Push timed out'
log and duplicate unread floods).

Hash the exact plaintext span that is encrypted and sent, plus the
client pubkey. Verified against openhop_core's TextMessageHandler: the
ACK it emits for a pushed post now matches the stored pending_ack_crc.

Fixes #286
2026-07-07 10:35:28 -07:00
agessaman 0404b3ab44 fix: add blank-password read-only guests to the room ACL
A blank-password login replied success (read-only guest) without ever
creating an ACL entry or storing the ECDH shared secret. The client app
believed it was logged in, but the room server's text handler and sync
loop only see ACL members: the client's posts were dropped without a
delivery ACK (send shows failed) and posts were never pushed to it.
Rooms with only an admin password configured were fully affected since
every guest login is blank-password.

Add the guest to the ACL with guest permissions, the shared secret, and
sync_since (mirroring the password path), reject when the ACL is full,
and refresh activity timestamps on repeat blank logins.

Refs #286
2026-07-07 10:35:01 -07:00
agessaman 3a29061e24 fix: tolerate openhop_core without QueuedMessage.sender_prefix
Installed openhop_core releases predating the sender_prefix change
(paired with fd43d86) reject the kwarg, so restoring queued messages
raised TypeError and aborted companion init. Detect support via the
QueuedMessage signature and drop persisted prefixes with a warning on
older cores instead of failing the boot.
2026-07-07 07:53:49 -07:00
agessaman e6d4b68d01 fix: fail companion init loudly when persisted state cannot be loaded
A transient SQLite error during boot made companion_load_channels/
contacts/messages swallow the exception and return [], which is
indistinguishable from "no data". The Public-channel backfill then ran
over the empty store, so clients saw their channels wiped and later
saves could overwrite the persisted state.

- companion_load_{contacts,channels,messages} now return None on error
  vs [] for genuinely empty, and log the companion hash
- add companion_count_{channels,messages} helpers
- extract shared _restore_companion_state used by both the boot and
  hot-reload companion paths; each load is cross-checked against the
  table's row count for the hash, retried once after a short delay,
  and raises CompanionStateLoadError if it still cannot load, aborting
  companion init (and the Public backfill) instead of starting empty
- log restored row counts per companion; log when the channel store
  rejects a persisted channel (unchecked channels.set return)
- trim_companion_contacts_to_fit refuses to trim on a failed load
2026-07-07 07:43:27 -07:00
agessaman fd43d86ea8 fix: persist sender_prefix for signed room posts
TXT_TYPE_SIGNED_PLAIN room posts carry a 4-byte author pubkey prefix
(QueuedMessage.sender_prefix, added in openhop_core). The SQLite
persistence path dropped it, so posts replayed from persistence showed
a zero-padded author prefix in the app frame while posts synced from
the live in-memory queue were correct.

- add sender_prefix column (hex text, default '') to companion_messages
  with an ALTER TABLE migration for existing databases
- store/return the prefix in companion_push/pop/load_messages
- pass sender_prefix when rebuilding QueuedMessage from persistence in
  the frame server and the startup preload paths
- add round-trip, default, migration, and rebuild tests
2026-07-06 22:46:49 -07:00
agessaman 700a38b8c1 refactor: use public max_size property for offline-queue retention
Prefer MessageQueue.max_size (new public property in openhop_core) over
the private _max_size attribute, keeping a getattr fallback for older
cores that predate the property.
2026-07-06 16:38:45 -07:00
Rightup 8b3894d2d5 fix: remove duplicate import statements in test files 2026-07-04 23:41:51 +01:00
Rightup daec7f0ebc feat: implement neighbor discovery session management and API endpoints 2026-07-04 23:41:33 +01:00
Rightup ae68112377 - Refactored ACL authentication flow with shared helpers for replay detection and session updates.
- Changed blank-password login behavior to create/manage guest sessions (when read-only is enabled), including replay protection and session timestamp tracking.
- Preserved and centralized `sync_since` handling during successful auth/session updates.
- Updated login handling to return explicit `(success, permissions)` and reset room-server sync guard state in SQLite on successful room-server login.
- Updated identity/banner output in mesh CLI from `pyMC_*` to `openHop_*` and adjusted default version fallback.
- Extended path handling to support encoded path-length semantics via `PathUtils`, with legacy fallback support for older/malformed packets.
- Added bundled ACK extraction from PATH payload extras and callback-based ACK propagation.
- Hardened room-server push logic: max-failure early skip, corrected expected ACK CRC calculation, path encoding compatibility, persisted sync/last-activity fields, and passed expected CRC + timeout into packet injection.
- Enhanced packet router ACK flow with dispatcher ACK registration helper, support for multipart ACK wrapper handling, configurable ACK wait timeout/CRC in injection, and ensured PATH helper processing always runs.
- Updated daemon wiring to pass ACK callback into `PathHelper`,
- make dispatcher dedupe configurable (prevent dbl deduping), and only register duplicate logging hook when dedupe is enabled.
- Expanded tests to cover guest blank-password replay tracking, updated room-server injector ACK expectations, and new duplicate-logging-hook gating behavior.
2026-07-02 16:32:32 +01:00
Rightup 34747d2610 feat: add packet retrieval by ID endpoint and corresponding database methods 2026-07-02 16:18:54 +01:00
Lloyd 823308aa3f fix: update drop reason handling in PacketRouter and RepeaterHandler 2026-06-29 15:48:19 +01:00
yellowcooln 4d095dad42 fix: update Docker image branding 2026-06-26 09:10:58 -04:00
Lloyd 27ccf5453d refactor: update GitHub owner to openhop-dev and enhance changelog error handling 2026-06-25 21:39:08 +01:00
Lloyd 42cd75e6b0 refactor: enhance logging and error handling in API endpoints and HTTP server 2026-06-25 21:26:29 +01:00
yellowcooln 432b00906c fix: satisfy pre-commit after openHop base sync 2026-06-24 20:36:23 -04:00
yellowcooln af88459f29 merge: sync with openHop refactor base 2026-06-24 20:35:06 -04:00
Lloyd 2b67dea96b refactor:rename-project-to-openhop 2026-06-24 23:27:49 +01:00
yellowcooln 44a2d2f72f feat: add system info to hardware stats sensor 2026-06-24 16:23:50 -04:00
yellowcooln b4b44831b0 feat: integrate openHop Glass inform policy sync 2026-06-24 15:17:41 -04:00
Björkan f1e860d17e feat(presets): add Meshat.se broker preset 2026-06-24 07:51:28 +02:00
Lloyd c761c425d1 Merge branch 'pr-294' into dev 2026-06-23 08:56:33 +01:00
Lloyd 018f425dc1 feat: data redaction in log messages and update related tests 2026-06-23 08:52:41 +01:00
Lloyd 4a8876a95e feat: implement login throttling with exponential backoff and enforce minimum admin password length 2026-06-23 08:52:40 +01:00
agessaman cd763e2cac feat: implement threaded stats broadcasting in StorageCollector
- Introduced a dedicated thread for broadcasting aggregate statistics to WebSocket clients, improving performance by offloading heavy queries from the packet write path.
- Updated the _publish_packet_sync method to ensure only fast, per-packet operations are executed, while the stats are handled separately.
- Added methods for broadcasting stats at intervals and managing the lifecycle of the stats thread.
- Enhanced unit tests to validate the new stats broadcasting behavior and ensure correct functionality under various conditions.
2026-06-18 21:38:20 -07:00
Yellowcooln 211fa51cd6 merge: sync PR branch with upstream dev 2026-06-16 11:42:36 -04:00
Yellowcooln b557116fdf fix: move modem CRC baseline into radio wrapper 2026-06-16 11:22:34 -04:00
Yellowcooln 1881ad9b93 feat: derive modem battery percent from voltage 2026-06-15 20:39:22 -04:00
Yellowcooln 1c186d7feb fix: throttle only pyMC modem sensor polling 2026-06-15 18:34:05 -04:00
Yellowcooln f2b7d254a7 fix: slow sensor polling to 60 seconds 2026-06-15 18:32:12 -04:00
Yellowcooln 642c019076 fix: preserve modem GPS satellites in view 2026-06-14 19:32:41 -04:00
agessaman dcaa4ac949 Refactor contact trimming logic for improved readability by consolidating function calls into single lines. Update related test cases for consistency. 2026-06-14 15:50:03 -07:00
Yellowcooln dde487bce3 fix: add generic PyMC modem stats sensor 2026-06-14 18:00:15 -04:00
Yellowcooln 77fc244895 fix: baseline PyMC modem CRC stats 2026-06-14 18:00:15 -04:00
agessaman 23078de78b Enhance contact import logic to respect max_contacts limit and trim excess entries. Update tests to validate trimming behavior and ensure correct handling of favourites during import. 2026-06-13 18:26:35 -07:00
Yellowcooln aeea4bb3f8 Format OpenAPI identity test 2026-06-09 16:10:37 -04:00
Yellowcooln 063c8eeb8c Fix companion identity OpenAPI contract 2026-06-09 15:50:09 -04:00
Lloyd 99a04295da Merge pull request #287 from agessaman/kiss/tuning-options 2026-06-09 19:33:47 +01:00
Lloyd 2b7b2b5b4e feat:add channel sender option to policy 2026-06-09 13:51:18 +01:00
agessaman 183650228e feat(config): add optional KISS CSMA tuning parameters
- Updated `config.yaml.example` to include optional KISS key-up and CSMA tuning parameters.
- Enhanced `get_radio_for_board` function in `config.py` to forward KISS tuning settings to the modem firmware when specified.
- Added tests to verify correct forwarding of KISS parameters and omission of unset values in `test_radio_config.py`.
2026-06-08 21:25:26 -07:00
Lloyd 00682e8086 Merge pull request #282 from agessaman/companion/advanced-settings 2026-06-06 18:09:00 +01:00
agessaman f3146ebc14 fix(companion): clean up ruff errors 2026-06-06 09:44:55 -07:00
agessaman ea6e660f34 refactor(api_endpoints): improve sqlite_handler retrieval logic
- Updated the logic for retrieving the sqlite_handler in APIEndpoints to use a safer approach with getattr, ensuring compatibility with the daemon_instance.
- Adjusted test case to include an additional parameter in the sqlite.companion_push_message assertion for consistency.
2026-06-06 09:39:30 -07:00
agessaman dac60443f0 feat(companion): implement contact trimming and retention policies
- Introduced `enforce_companion_contact_capacity` to manage contact limits during companion loading, with an option to trim non-favourite contacts when exceeding capacity.
- Updated `SQLiteHandler` to support message retention limits, allowing for automatic trimming of older messages based on `offline_queue_size`.
- Enhanced API endpoints to handle contact trimming on overflow, providing feedback on trimmed contacts during updates.
- Added utility functions for selecting and trimming contacts while preserving favourites.
- Improved logging for contact management actions and errors related to capacity.
2026-06-05 21:39:11 -07:00
Lloyd b3119f97f4 Merge branch 'pr-281' into dev 2026-06-05 16:25:15 +01:00
Lloyd da95c67cef fix: improve error logging for invalid policy entries and adjust test configuration 2026-06-05 16:23:18 +01:00