- Introduced `jwt_ttl_seconds` and `jwt_renewal_interval` settings in `config.ini.example` for global JWT management, allowing for better control over token expiration and renewal intervals.
- Updated documentation in `packet-capture.md` to clarify the usage of global and per-broker JWT settings, enhancing user understanding of authentication configurations.
- Refactored `PacketCaptureService` to incorporate new JWT settings, ensuring consistent handling of token lifetimes and renewal processes.
- Updated the `track_contact_advertisement` method to return a structured result indicating success and duplicate packet status, improving clarity in handling contact advertisements.
- Adjusted the `MessageHandler` to utilize the new result structure, allowing for better decision-making based on tracking outcomes.
- Enhanced unit tests to cover new behaviors and ensure correct handling of duplicate packets and advertisement tracking results.
Scheduled cron jobs now pass the cron key into the send path, apply a
deterministic [0, N) second delay from scheduled_message_max_stagger_seconds
(default 1.5), and call send_channel_message with skip_user_rate_limit=True
so simultaneous jobs are not dropped by rate_limit_seconds. Per-channel and
bot_tx limits still apply. Document the new Bot key in config.ini.example;
tests assert kwargs, skip flag, and stagger behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Introduced `reply_prefix` to prepend a customizable string to path command replies, supporting placeholders for dynamic content.
- Added `minimum_path_bytes` setting to control the resolution of repeater names based on the number of bytes per hop, enhancing path command behavior.
- Updated relevant documentation and translations to reflect these new configuration options.
- Implemented unit tests to ensure correct functionality of the new features.
Route process_message keyword/RandomLine sends through send_response so
reply_scope reaches set_flood_scope; add optional command_id to
send_response for transmission tracking.
- Updated the scheduled message format in `config.ini.example` to support 5-field cron expressions and preset aliases, replacing the deprecated HHMM format.
- Improved the `MessageScheduler` class to parse and validate new schedule formats, logging warnings for deprecated usage.
- Adjusted the `ScheduleCommand` to display scheduled messages with their respective cron or preset labels.
- Added unit tests to ensure correct parsing and handling of various schedule formats, including legacy HHMM and cron expressions.
- Replaced the use of AdvertFlags enum for flag parsing with bitwise operations to handle invalid values correctly.
- Updated the parsing logic in both MessageHandler and MapUploaderService to use boolean flags for better clarity and performance.
- Adjusted error logging to use warnings instead of errors for parsing issues, enhancing the logging strategy.
- Added unit tests to ensure correct parsing behavior for edge cases with invalid flag values.
Add bridge_outbound posting, BaseServicePlugin.send_external_notifications,
and RepeaterPrefixCollision discovery vs collision routing with silence_mesh_output.
- Added configuration options `mqtt_skip_unparseable_packets` and `advert_require_valid_signature` to control MQTT publishing behavior based on packet validity.
- Updated `decode_path_len_byte` function to return `None` for reserved size codes, improving path length validation.
- Implemented logic in `PacketCaptureService` to skip publishing unparseable packets and ADVERT packets with invalid signatures.
- Introduced `verify_meshcore_advert_ed25519` function for signature verification of ADVERT packets, with corresponding unit tests to ensure functionality.
- Enhanced documentation to reflect new configuration options and their effects on packet processing.
- Implemented validation for the `channel_name` field to ensure it is not empty when updating feeds, raising a ValueError if validation fails.
- Added test cases to verify that updates to `channel_name` persist correctly and that attempts to set an empty `channel_name` are rejected with an appropriate error response.
- Modified the SQL insert statement in the RepeaterManager class to include `public_key` and `name` fields, ensuring compatibility with the new schema.
- Updated corresponding test cases to reflect changes in the database operation, maintaining the integrity of the purging log functionality.
- Introduced a new configuration option `default_city` in `config.ini.example` for fallback city names when no location is provided.
- Updated `wx_command.py` and `wx_international.py` to utilize the `default_city` for location disambiguation, enhancing user experience when companion location is unavailable.
- Improved logging to reflect the use of default city or bot location as fallback options.
- Replaced direct imports of `pytz` with dynamic imports for better compatibility.
- Updated type hints for server and loop attributes in the DARC MoWaS service.
- Enhanced XML handling by specifying `xml.dom.minidom.Element` in method signatures.
- Improved message processing logic to handle missing channels and ensure valid area descriptions.
- Refactored `_child_text` function to accept both `Document` and `Element` types for better flexibility.
- Adjusted unit tests to reflect changes in the DARC MoWaS service structure.
- Updated the TraceCommand class to support parsing of 1-byte, 2-byte, and 3-byte hex node paths.
- Improved the _extract_path_from_message and _parse_path_arg methods to handle multibyte node formats and enforce consistent length checks.
- Enhanced help text and usage examples to reflect new path formats.
- Added unit tests for multibyte path parsing and reciprocal path building to ensure correct functionality.
- Added configuration options to specify minimum path byte length requirements for the path, test, and multitest commands.
- Introduced methods to enforce these requirements and handle failure responses.
- Updated the packet capture service to correctly calculate packet hashes using the raw wire byte length.
- Enhanced unit tests to verify the correct behavior of the new path byte length logic.
We implement support for the DARC MoWaS service that distributes
emergency messages from the German BBK via the "Warnmultiplikator"
interface to Meshcore channels. This service is push-based and receives
alerts on /api/alert, which are then formatted similar to cell-broadcast
messages (without modification of the text) and re-distributed on
Meshcore.
Signed-off-by: Felix Moessbauer <felix.moessbauer@gmail.com>
- Added a new migration to include a 'details' column in the 'purging_log' table for improved logging of actions.
- Refactored the `log_purging_action` method in `RepeaterManager` to handle both new and legacy schemas, ensuring compatibility with the updated database structure.
- Updated `MessageHandler` to utilize the new logging method, replacing direct database updates with a unified logging approach.
- Added tests to verify the presence of the new column and the correct functionality of the logging mechanism across different scenarios.
- Updated `send_dm` method to first attempt contact resolution by name, and if that fails, fallback to resolving by public key prefix.
- Improved logging to indicate the method of recipient resolution used.
- Added tests to verify the new recipient resolution logic, ensuring correct behavior when looking up contacts by public key prefix and handling failures appropriately.
- Enhanced configuration options for `auto_manage_contacts` to support 'device' mode, allowing firmware to handle companion auto-addition and favourite hygiene.
- Updated `MessageHandler` to track new companions based on the `auto_manage_contacts` setting, with distinct behaviors for 'false', 'device', and 'bot' modes.
- Introduced scheduled jobs in `MessageScheduler` for device mode to manage firmware preferences and favourite keys with specified delays.
- Modified `RepeaterManager` to skip companion auto-purge in device mode, ensuring firmware manages contact slots effectively.
- Added tests to validate new behaviors and configurations, ensuring robust handling of contact management across different modes.
Simplifies find_recent_rf_data so the sample it returns is always a single
wire observation — snr, rssi, raw_hex, and routing_info all belong to the
same decoded copy. The #80 fix stays intact via the two earlier invariants:
unmatched correlation_key returns None (no fallback to an unrelated recent
packet), and the no-key DM path is constrained to a narrow
rf_fallback_window.
An earlier iteration tried to enrich routing_info with the longest observed
same-packet_hash forward, but that would have left message_stats rows with
hops sourced from the matched observation while path was a different
forward's — an internal skew visible in the web viewer and !path output.
The enrichment is documented in TODO.md as a v0.9.1+ option-C follow-up
that must also sync message.hops for consistency.
Regression tests in tests/test_message_handler.py::TestFindRecentRfData
cover: return-None on unmatched key, narrow-fallback-window rejection of
stale samples, and the no-cross-wiring assertion for same-packet_hash
forwards.
Made-with: Cursor
- Rewrite test_subscribe_packets/messages_emits_status_ack to match the
silent subscription UX from 1ee84f2.
- Reconcile Python version: requires-python>=3.10, ruff target py310, CI
matrix adds 3.13, pyupgrade UP0xx ignored pending a separate typing-rewrite
PR; fix two B905 zip(strict=...) lints.
- Issue #80 fix in find_recent_rf_data: return None when correlation_key is
provided but unmatched; prefer the longest observed path among samples
sharing a packet_hash; narrow the no-key fallback to a configurable
rf_fallback_window (default 2s).
- Issue #161: lower shipped max_response_hops default 10 -> 7.
- Add CHANGELOG.md, restructure BUGS.md around a ## v0.9.0 Fixed Bugs
table, prune crossed-out duplicate outstanding rows, and add a
Deferred-from-v0.9.0 triage section to TODO.md.
- Untrack coverage.json and add it to .gitignore.
Made-with: Cursor
Introduced optional timeout settings in the configuration for various web viewer operations, including edge and node post timeouts, SQLite connection timeout, and requeue timeout. Updated the web viewer integration to utilize these settings, enhancing flexibility and reliability. Added commands to inspect the resolved configuration with sensitive keys redacted, and updated documentation accordingly.
Added asyncio timeout handling for sending startup and interval-based adverts, improving reliability by recording failures on timeout. Updated relevant tests to ensure coverage for timeout scenarios and increment failure counts appropriately. Introduced a new Radio Reliability panel in the web viewer for monitoring radio status.
Modified the config item retrieval in BotDataViewer to use raw=True, ensuring that literal '%' characters in configuration values are not subject to interpolation. Additionally, removed the breadcrumb navigation from the admin configuration template for a cleaner UI. Added a test to verify that '%' in values does not cause server errors.
Introduced a new test class, TestAdminConfig, to verify the loading of the admin configuration page and ensure sensitive information like passwords is redacted in the response. This enhances test coverage for the admin configuration functionality.
- Add allow_private param to validate_external_url (alias for
allow_localhost) to unblock web viewer SSRF guard using allow_private=
- Block non-globally-routable IPs (RFC 6598 100.64.0.0/10 CGN) on
Python 3.10 which does not classify them as private or reserved
- Remove tests for greeter DB tables and admin_config template that
depend on features not present on this branch
- USE-05: Add /api-explorer page listing all ~65 API endpoints in 9
categories (System, Contacts, Mesh, Channels, Feeds, Radio, Admin,
Maintenance, Config, Greeter) with method badges, descriptions, and
curl example modal. Filter bar and collapse per section. Nav item
added to base.html.
- USE-06: Three targeted error-message improvements:
1. 500 handler now returns user-friendly HTML page (error.html) for
browser requests and sanitized JSON for API/JSON requests instead
of a bare string.
2. Feed processed-items query failures promoted from logger.debug to
logger.warning so operators see them in normal log output.
3. Global JS fetch interceptor in base.html redirects to /login?next=
on any 401 response, handling session expiry mid-page.
- Fix pre-existing test bug: test_reload_endpoint_success mock return
value did not match actual code message from reload_config.
Updated the BotDataViewer class to utilize a context manager for database connections, enhancing resource management. Additionally, refactored test files to implement a centralized approach for managing SQLite connections, ensuring proper cleanup after tests. This change improves code maintainability and reliability across the application.
Introduced a new command structure for RandomLine entries in the website generation process, allowing for dynamic rendering of random lines based on configuration. Updated the configuration file to include a new category option for commands and enhanced documentation to reflect these changes. This addition improves the command reference organization and user experience on the website.
Introduced a new configuration option `cmd_reference_url` in the Cmd_Command section, allowing users to override the default `cmd` output with a link to a full documentation page. Updated the CmdCommand class to utilize this new setting and modified related documentation and tests to ensure proper functionality.
- Make MeshCoreBot.stop idempotent; remove duplicate stop from start().
- Avoid web viewer restart during shutdown; gate main-loop restarts.
- Fix packet capture MQTT callbacks to log each broker’s host.
- Only shutdown APScheduler when running; silence double-shutdown noise.
- Add regression tests in tests/test_shutdown_reliability.py.
Make outbound send suppression consistent by honoring both radio-offline and zombie states across command-manager and scheduler paths. Preserve strict SSRF defaults while adding explicit private-feed URL opt-ins, persist allow_local_smtp from notifications config writes, reconcile zombie alert setting precedence, and replace deprecated UTC timestamp calls with timezone-aware UTC usage.
Removed the fortune command and its associated files, transitioning to existing new random lines command that retrieves fortunes from a different file structure. Updated configuration settings in config.ini.example to reflect this change, including the new file path for fortunes. Adjusted the .gitignore to accommodate the new directory structure for random lines. This refactor enhances the organization of fortune-related content and improves maintainability.
Updated the path validation logic in security_utils.py and web_viewer/app.py to include additional dangerous prefixes, specifically targeting private directories. This change aims to strengthen security by preventing access to sensitive system paths. Additionally, modified the test for posting feeds to mock the external URL validation, ensuring consistent behavior during tests.
Adds a new !fortune command that picks a random fortune from a
configured BSD-format fortune file (entries separated by a line
containing only %). The parser handles: % as separator or terminator,
multi-line fortunes, trailing whitespace, and % embedded mid-line.
Path validation via validate_safe_path() blocks path traversal before
any file open. Command is auto-discovered by the plugin loader.
Config section [Fortune_Command] added to config.ini.example with
enabled and file keys. Default file: data/fortune/fortunes.txt.
22 tests cover: parsing edge cases, security path rejection,
can_execute enable/disable, execute happy path, empty file fallback,
and plugin metadata.
Fortune file: BSD V8-fortunes (fortunes-freebsd-classic)
Source: https://github.com/HubTou/fortunes-freebsd-classic
1,903 fortunes drawn from the classic BSD UNIX fortune database.
Content note -- data/fortune/fortunes.txt (1,903 fortunes):
No racist, lewd, or pornographic content found. Six lines flagged
during review as mildly coarse; retained but noted here for reference
in case a future maintainer wishes to remove them:
L1763: Some days chicken salad -- some days chicken shit.
L2289: We retard what we cannot repel, we palliate what we cannot
cure. -Johnson
L3009: In New York they signal the wrong way just to fuck you up.
-David Yost
L3161: Sure [Somoza]'s a son-of-a-bitch, but he's OUR
son-of-a-bitch. -F.D. Roosevelt
L3305: When better machines are built, jks will break them, and td
will bitch about it.
L3589: It's the thought, if any, that counts! -Dick Grantges
("Dick" is a proper name, not a slur)
- core.py: add _BotAdminServer daemon thread (Flask, 127.0.0.1 only,
bearer token auth); POST /api/admin/reload calls reload_config() and
returns JSON {success, message}; GET /api/admin/health; started from
start() when [Admin] enabled = true and token is set
- scripts/reload_config.sh: curl wrapper for the reload API; reads
port/token from config.ini [Admin] section; exits 1 on rejection
- tests/test_core.py: TestBotAdminServer — 7 tests covering server
creation, missing token guard, reload success/failure/auth, health
Clean up residual cherry-pick conflict markers and keep SMTP guidance in config templates brief while preserving full behavior in code and tests.
Made-with: Cursor
Fix ruff violations (import sort, unused imports, whitespace) in
backup_database.py, generate_website.py, meshcore_bot.py,
migrate_webviewer_db.py, packet_capture_service.py, version_info.py,
scripts/config_tui.py, scripts/update_todos.py, and validate_config.py.
Fix mypy stale type-ignore and remove unused imports in test files.
Add is_radio_zombie/is_radio_offline mock attributes to command_manager
test fixtures to prevent truthy Mock early returns.
Add SSRF host validation to maintenance.py send_nightly_email and
scheduler.py send_zombie_alert_email using validate_external_url().
New allow_local_smtp config key permits private-IP SMTP for local
relay setups.
Add sanitize_name() to security_utils and apply it to all log calls
in message_handler, repeater_manager, path_command, solarforecast_command,
command_manager, and discord_bridge_service to prevent log injection.
Move nightly email logic from duplicate scheduler._send_nightly_email()
into the canonical maintenance.py implementation, removing the duplicate.
Update tests to call maintenance.send_nightly_email() directly.
Add validate_external_url allow_private parameter with support for
loopback, RFC1918, CGN, and link-local address ranges.
The send_channel_message test was leaving bot.is_radio_zombie as an
unset MagicMock attribute, which evaluates truthy and triggers the
zombie-state early return before flood scope logic runs.
Add bot.is_radio_zombie = False to the mock setup so the function
reaches the set_flood_scope call as intended.
ff7917e incorrectly changed all test patches from
`scheduler.maintenance.run_db_backup` to `scheduler._run_db_backup`,
and rewrote `_setup` to bypass the delegation architecture upstream uses.
- Restore `_setup` to use `scheduler.maintenance.get_maint` side_effect
- Restore all 6 tests to patch `scheduler.maintenance.run_db_backup`
- Add `patch.object(scheduler.maintenance, "_get_current_time")` to
`test_weekly_on_wrong_day_does_not_run` to prevent Monday flakiness
in UTC CI environments (maintenance captures `_get_current_time` as a
bound method, so patching only `scheduler.get_current_time` is not
sufficient)