Skip to content

v4.9.2

Choose a tag to compare

@github-actions github-actions released this 28 Sep 12:41
· 3627 commits to master since this release
Immutable release. Only release title and notes can be modified.
Release Notes

Added

  • Network visualiser gains a radial view mode that pins nodes on deterministic hop rings around the local node, plus screen-space label decluttering so dense zoomed views stay readable.
  • Settings self-test gains a CBOR roundtrip check that exercises the RRC codec's encode, decode, and stream replay paths.
  • CI performance suite measures cold-load FCP, LCP, SPA route transition latency, API round-trip, and post-mount heap per page with per-page budgets, plus a heap-growth spec that fails when a page leaks listeners, timers, or nodes across mount/unmount cycles.
  • NomadNet: local page nodes rescan their pages and files directories on a timer and on each incoming link, so content dropped in externally is served without a restart and removed content stops answering. Matches upstream NomadNet's page_refresh_interval behavior.
  • Backend fault-injection suite covers malformed RRC wire traffic, reconnect timer storms, hub store corruption, page-node rescan failures, crawler garbage inputs, link-cache teardown errors, and callback exceptions.

Security

  • HTTP-set command_plugins_path is jailed under storage so remote callers cannot point the plugin loader at arbitrary Python files.
  • Reticulum rpc_key and interface secrets are served only to loopback or authenticated callers, and a redacted GET round-trips through PUT via a sentinel so non-privileged edits cannot erase real values.
  • auth_session_epoch is stamped into session cookies and checked on HTTP middleware and the WebSocket upgrade, so password, auth-toggle, and setup changes revoke outstanding sessions. Session secret files are restricted to 0600.
  • Translation-pack extraction is bounded by per-member, total, and file-count caps with streamed copies.
  • /api responses send Cache-Control: no-store, the static auth bypass is scoped to actual asset suffixes, and remote markup rendered into the main document loses id/name attributes so archived pages cannot clobber window globals.

Fixed

  • Messages: opening a raw outbound message no longer 404s once it leaves router memory (delivered or post-restart). The paper URI endpoint rebuilds the signed lxm:// URI from the stored row, preserves the original timestamp so the message hash and ingest deduping hold, verifies the repacked hash against the stored row, and skips the request entirely for inbound messages, which can never be signed by the local sender.
  • Messages: resend preserves title, reply quotes, reactions, app extensions, and correctly decomposed telemetry, and other sessions are told when the old failed row is deleted.
  • Messages: cancel validates the hash, reaches forwarding-alias routers, and reconciles rows stuck in generating/outbound/sending to cancelled after a restart instead of returning ok while nothing changed.
  • Messages: startup recovery fails sent+direct rows that could never advance after restart, and a same-hash inbound delivery can no longer demote an outbound row to incoming or repoint its peer.
  • Messages: hash lookups normalize case across message, attachment, spam, and announce paths.
  • Messages: queued sends snapshot peer and composer state so a cleared composer or peer switch cannot send into the wrong conversation, pending placeholders dedupe correctly, inbound duplicates are dropped, and audio decode is serialized with contexts closed on unmount.
  • Messages: paper URI generation and URI ingest over WebSocket were fire-and-forget. A failed send or dropped reply left buttons disabled or a spinner forever. Sends now check the result, toast on failure, and bound the wait with a timeout.
  • Android: bridge-backed buttons (WiFi Aware grant, nearby permission, native RNode flasher) were silently dead because the injected bridge sat inside a Vue reactive proxy. The bridge now marks itself non-reactive and binds methods to the raw instance.
  • Android: release APKs kept stripping org.meshchatx.locallink.* because the classes are only reached via jclass() from Python, so WiFi Aware stayed disabled in minified builds. R8 keeps them and a dex check gates the build.
  • Android: the native RNode flasher no longer shows a duplicate title hidden behind the status bar.
  • Reticulum: a second AutoInterface bind failure left a zombie singleton that killed every in-process restart. Recovery now releases interface sockets and resets singleton state before rebinding, a colliding interface is rejected at add time, and a guidance notice reports auto-disabled interfaces.
  • NomadNet: image loading now parses the NomadNet 1.4 whole-line image syntax (paren links with w/h/a/s/k/profile fields and percent widths) and sends the key field the /media protocol requires. Verified live against rns.recipes.
  • NomadNet: page and file download events are correlated by request id so stale transfers cannot feed replacement entries, and archive navigation performs full teardown.
  • NomadNet: requesting an unknown page or file from a local node opened a doomed link to the node itself. Local serving now resolves only canonical /page, /file, and /media paths, and the download handlers fail fast instead, reporting archive availability for pages.
  • Relay chat: prefs and drafts are scoped per identity, so hide-join/part and ignore state apply once the identity hash resolves, hub switches reset room state, the composer clears before send to end double-send and lost-text races, and debounced config writes survive identity switches.
  • Relay chat: hub auto-reconnect retried on a 60 s backoff cap forever, so a large set of unreachable hubs produced a constant stream of link and path requests. Backoff now doubles per failure up to a 15 minute ceiling with jitter, startup connects are staggered, path requests dedupe per hub, and a fresh hub announce resets the backoff so a recovering hub reconnects quickly. Manual connects reset the counter for an immediate retry.
  • Service worker: subframe requests are excluded from the shell navigation strategy and only shell documents or extensionless SPA routes use the fallback slot, fixing the stale-cache stuck Loading page. Updates reload exactly once, WebTransport falls back to WebSocket on session death, and a version-mismatched backend triggers a reload after reconnect.
  • Backend: websocket_broadcast from foreign loops forwards onto the owning client's loop, the self-test endpoint runs off the event loop so its own probes cannot deadlock, and the Windows AppContainer probe wait is bounded.
  • Backend: deleting an identity tears down its live context first, telemetry per destination is capped, and in-flight propagation-node tasks are cancelled on shutdown.
  • Electron: protocol links are stripped from backend argv and delivered to the renderer after load, certificate-error bypass is scoped to the local backend, DevTools shortcuts and hardware permissions are gated, and the Electron runtime version invalidates stale caches on upgrade.
  • UI: context menus dismiss on click-off and re-right-click again, popup carets stay off rounded corners, and the map drawing toolbar stays pinned at the top on xl screens.
  • UI: stuck-state follow-through in MiniChat (send failures now toast and fresh timestamps render), ContactsPage lxma import, NomadNet archives spinner, and the archived-pages flush result toast.
  • CI: alpine APKs are built without fpm and verified by actually installing them in an apk-tools container.
  • Locale files gained the missing aware/nearby permission strings in all 15 locales.
  • Backend: a wedged SQLite pool could leave every API call answering 503 until a manual restart. When WAL or SHM files get unlinked under open connections, every statement fails with a disk I/O error and per-connection retries never recover. The provider now spots failures that persist on fresh connections, resets the whole connection pool at once, and if that is not enough restarts the process. Restart attempts are bounded, so a permanently broken store keeps serving retryable 503s instead of crash-looping.
  • Relay chat: a malformed hub or client envelope could raise inside a packet handler and break session processing. Client and server dispatch now contain handler errors per packet, and the announce-reset and path-request rate limits use never-fired sentinels so the first retry is not skipped on hosts with low uptime.
  • HTTP: the safe file response raises a real error instead of asserting when aiohttp hands back no writer.
  • CI: Docker builds install pnpm 12 through npm since the pinned node image's corepack cannot shim its native binary, and the dev container does the same.
  • CI: the shared Node setup keys its corepack cache by runner architecture, so an arm64 pnpm binary can no longer be restored onto the x64 macOS build runner.

Changed

  • The Landlock sandbox now uses landlockpy instead of the custom ctypes plumbing. The enforced filesystem policy is unchanged and Android is unaffected.
  • Relay chat's CBOR codec moved from cbor2 to cborx, a zero-dependency RFC 8949 implementation with an optional compiled fast path. Canonical wire encoding is unchanged, decode rejects trailing bytes instead of ignoring them, and Android packages cborx through a Chaquopy recipe instead of the cbor2 wheel.
  • Visualiser layout spacing widened to match node size, WASM and JS paths gained LOD color, NaN guard, edge-filtering, and dead-scene fallback parity, and visualiser.wasm was rebuilt.
  • UI lighthouse, performance, and heap suites run against the production bundle instead of the Vite dev server, and service workers are unregistered before audits so scores cannot be nulled by a controlled navigation.
  • Backend: the eight per-identity periodic loops (auto-announce, propagation sync, crawler, auto-backup, telemetry, retention, flood cooldown, auto propagation selection) now share one background event loop instead of one thread each. Backups, retention sweeps, and announce table reads run in worker threads so they cannot stall the shared loop. This cuts several threads and thread-local database connections per identity.
  • Backend: debug log writes to SQLite are batched into one transaction per flush, the retention sweep runs at most every ten minutes instead of every five seconds, and MESHCHAT_LOG_DB=0 disables database logging entirely. On SD-card installs this removes a steady stream of small writes.
  • Backend: after identity setup finishes, startup objects are frozen out of the cyclic garbage collector's scan set, and the periodic cleanup calls malloc_trim so freed memory returns to the OS instead of sitting in allocator arenas.
  • Docker images and the Raspberry Pi installer set MALLOC_ARENA_MAX=2 and OPENBLAS_NUM_THREADS=1, and the Pi guide documents both plus MESHCHAT_LOG_DB=0 for low-memory and SD-card deployments.
  • Backend: the LXST telephony stack, numpy, and its audio backends no longer load at startup. The web audio bridge sits behind a lazy proxy that constructs it on first call, and telephone and voicemail resolve their LXST symbols on demand. Text-only installs keep tens of MB of memory and the OpenBLAS worker threads out of the process. If the audio stack fails to initialize or a bridge call keeps raising, the proxy disables audio for the session instead of letting errors reach the messaging paths.
Changelog

No previous tag found; changelog omitted.

SHA256 Checksums
Asset SHA256
meshchatx-frontend.zip d8dfa44c89c0b423f64aad95ba78ff92e0c1771ea6b812de4398cf749379c066
ReticulumMeshChatX-v4.9.2-win-installer.exe.blockmap.cosign.bundle 920b89d3c54d1ad50c0eda1dc4291fd9ad588cc00f0a686247a9035bcc9e41cf
ReticulumMeshChatX-v4.9.2-linux-x86_64.flatpak 4b8475ae04f9d5038495f426ee5456c7c94c41e59332d3ea9ea4b9a5d2a5944e
ReticulumMeshChatX-v4.9.2-mac-arm64.dmg 24a5f38c8438a252ef3983423a0e51ae5ce7681599927d5342b92b32be5c78ce
ReticulumMeshChatX-v4.9.2-linux-arm64.AppImage 4ac09143bbba91fb038dcdfc2c53290c19052eb4908ae8aa110f83a7f60ff575
meshchatx-desktop-v4.9.2.intoto.jsonl 9eeeb1c295019ce5708bd05034beae44bcc8ce5b6aff5576ddcaeabc4d85fe84
ReticulumMeshChatX-v4.9.2-win-installer.exe ac6c6b35c05668692ea6965e0757fae6b275f86c38b79d1186eedb8906bf58fc
reticulum_meshchatx-4.9.2-py3-none-any.whl 0072dff4dff1b7285d62f927fff9a2062c0c43182fbb06e85879f95f7a6e5f42
ReticulumMeshChatX-v4.9.2-android-universal.apk f79f36947aa4b7a3787c54bf5843d0d755844b93b83401d77054b3a47ea9ed55
ReticulumMeshChatX-v4.9.2-win-installer.exe.blockmap a476af38eeed10379e85d073ec92247167cadbffacb5f34f496e0df91e5e138e
latest.yml.cosign.bundle ac0d7e795e37d311ee6e7c872a1397c655edecec9c91a789976c79f9eded5db9
ReticulumMeshChatX-v4.9.2-mac-arm64.dmg.cosign.bundle f02a9797f6b54544e30ee2b0f831b56967bbd2289b5310ae7eaab866f95dfbeb
ReticulumMeshChatX-v4.9.2-linux-arm64.deb 8323a4a126abc5a95d534e4b01d5cfc6cda7e8b099ad8865e971a3e9f51f8bb0
ReticulumMeshChatX-v4.9.2-mac-x64.dmg 0e9f6ba686a96ff232b98af21825e4696d218c341127a00cfea6709020157911
meshchatx-linux-v4.9.2.intoto.jsonl bba24bda1075c36cfde264721369bd7b446fb949af6dba3383bd3ae5319eeb37
ReticulumMeshChatX-v4.9.2-win-portable.exe 859bda2ce408220db7b83fea051265852666d85641abe55da1a1e7e6138cc268
ReticulumMeshChatX-v4.9.2-win-portable.exe.cosign.bundle 25802092c6fa1d3a3a313346aa8cabd7d46d2c1177e8abf6ebf62041f8828deb
ReticulumMeshChatX-v4.9.2-linux-alpine-x64.apk 2592d4858dcf3e414c8c72151fb7f9cdb41f053354d320c70c3b29c01588777a
ReticulumMeshChatX-v4.9.2-linux-x86_64.rpm ef5d0fed4c5c8c1b5efe334c83f5981573a26b59ffbb68553439ec69baaf27e1
latest.yml 7ad057d5541778805bc43ef44f1bf3d856deff4bbf171e22ba56a895d2a8d2c0
ReticulumMeshChatX-v4.9.2-linux-amd64.deb b81ef3c37204c83458925370327cb688d0925970fc7269f5ac7bb677ee3da6e1
meshchatx-py314-linux-x64.pyz 1382c878fdd25395a614a85f9107c32a3567b8fd93d8f9bb0b56ea5a07e9f5d0
meshchatx-py311-linux-arm64.pyz bd1c358f8e23e6d2c7a64312dd03a7771f51c8397ff5117fadcd380f558fbffb
ReticulumMeshChatX-v4.9.2-linux-x86_64.AppImage 1eef11101e4e73a8dfa7cc7c3ce859dafd16d8dd8a93cec69162896b5d9d5cf2
openvex.json d6aa027853ecbc974f8c52f64c4fa5c874724ad412bd33c77483cf167853077d
meshchatx-py314-linux-arm64.pyz 52bc98a87d1b236bedc7bbd41c3b1ee9f2da7dddc4512e527726177b1b94a9d1
ReticulumMeshChatX-v4.9.2-mac-x64.dmg.cosign.bundle ede105f8f985deb78cec5f6285881ca3011e58679a899fc8775444757e176b59
sbom.cyclonedx.json 29c5b064897caeb52ba63060c45e3a3787352f5eb1bf1e45bce3aa7a819c21d5
meshchatx-android-flatpak-v4.9.2.intoto.jsonl bceab907560307a079eca9e33f5cbe5aadbd1a05f1866b3ba74f077a2ceea733
meshchatx-py311-linux-x64.pyz 71675b8e5a5e44db1c652505f7bb35cb9412b8a3663792882458d3fb4002cf62
ReticulumMeshChatX-v4.9.2-win-installer.exe.cosign.bundle 1e5ce8b72979b8a06220902aa47f7b84b44ce2c176224cd0e29aee726a75245e
Verification
  • Cosign bundles (.cosign.bundle) are attached for keyless sigstore verification.
  • SLSA provenance (.intoto.jsonl) is available for supply-chain attestation.
  • Or verify manually using the SHA256 table above.