github Yeraze/meshmonitor v4.16.1-rc3

pre-release3 hours ago

MeshMonitor v4.16.1-rc3

⚠️ Pre-release. This is a release candidate for testing. Docker images are published without the :latest tag. Report anything you find on Discord or as a GitHub issue.

A security-led candidate. Four API endpoints checked permissions without a source id and then answered for whatever source the caller named in ?sourceId=, so an account holding a grant on any one source could read another source's data — DM counts, oldest-unread timestamps, and in the worst two cases the message bodies themselves. All four are fixed and each carries a regression test that was verified to fail without its fix. Alongside that, configuration search arrives across every settings page, waypoints can now raise an arrival alert with a radius and deduplication, and the Sources sidebar gains a "Mark all read" action that clears every source's unread DM badge in one request. On the build side the armv7 Docker image now compiles its JavaScript natively instead of under QEMU, cutting that leg by about 42%, and a new Retag workflow can re-point :dev at an already-built version in a minute rather than a forty-minute rebuild. A long-standing react-leaflet mock gap that had been failing CI intermittently for days is also closed. Eleven dependency bumps land too, including React 19.3.0 — now grouped in Dependabot so react and react-dom can never again be split into two PRs that neither merge.

Security

Four cross-source permission leaks, all the same shape — hasPermission called with no sourceId while the handler answered for a caller-supplied ?sourceId=:

PR Endpoint Exposed
#5227 GET /api/messages direct-message bodies
#5227 GET /api/messages/channel/:channel channel message bodies
#5225 GET /api/messages/unread-counts unread DM counts
#5225 GET /api/messages/first-unread oldest-unread timestamps

Reproduced against a real install before fixing. Scoping these gates locks nobody out: messages is a per-source resource, so a global (sourceId = NULL) grant never authorized anything through that path anyway.

Features

  • #5226 — per-page and cross-page configuration search (#5182)
  • #5228 — waypoint arrival alerts with a radius trigger and deduplication (#4750)
  • #5224 — "Mark all read" in the Sources sidebar, clearing every source's unread DM badge in one request (#5197). Added beside the existing visibility toggle rather than replacing it — that toggle is its own only control and also gates the 15-second poll.

Bug Fixes

  • #5203 — MeshCore DM and channel retries reuse the original senderTimestamp instead of minting a fresh one, so a retransmit is no longer delivered as a duplicate message (#5202). Also stops a NO_CHANNEL routing-error flood: the device push was addressed on the donor row's channel, which for an MQTT donor is a virtual channel number, not a radio slot.
  • #5219DashboardMap.test.tsx mocked react-leaflet without a GeoJSON export while the test renders a visible coverage layer, so the overlay threw asynchronously and tore down the React tree. It surfaced as an unrelated-looking "Unable to find a label with the text of: 3D Terrain" and had been failing CI intermittently for days.

CI / Build

  • #5207 — the armv7 image builds its JavaScript natively instead of under QEMU. Vite and tsc emit platform-independent output, so emulating them bought nothing; measured locally, 18m25s → 10m44s (−42%), with the produced dist/ verified byte-identical to the emulated build.
  • #5205 — raised the armv7 Docker timeout, which had been failing and silently preventing the multi-arch tag from publishing at all.
  • #5206 — new Retag workflow: re-point :dev (or any alias) at an already-built version in about a minute, instead of a full rebuild.

Dependencies

Eleven bumps, including React and React DOM to 19.3.0 (#5221). Dependabot had split react and react-dom into separate PRs; because react-dom refuses to run against a mismatched react, neither could merge alone — each failed all 1,272 test files at collection. They are now a Dependabot group, so the family always moves together.

Also: maplibre-gl 6.9.0, lucide-react 1.44.0, vite 8.3.0, es-module-lexer 3.0.2, the codeql-action group, the production-dependencies group, and the TypeScript ESLint packages.

Issues Resolved

  • #5202 — MeshCore retries generate new sender timestamp
  • #5197 — "Mark all as read" action for the Sources sidebar
  • #5182 — Add search to configuration pages
  • #4750 — Waypoint arrival notifications with radius trigger and deduplication

Upgrade Notes

No breaking changes, no migrations, no configuration changes. Upgrade in place.

Operators running multiple sources with non-admin accounts should take this one. The four permission fixes above are the reason this candidate exists: before them, a user granted messages:read on a single source could read other sources' direct messages by naming them in a query parameter.

Full changelog: v4.16.1-rc2...v4.16.1-rc3

🚀 MeshMonitor v4.16.1-rc3

📦 Installation

Docker (recommended):

docker run -d \
  --name meshmonitor \
  -p 8080:3001 \
  -v meshmonitor-data:/data \
  ghcr.io/Yeraze/meshmonitor:4.16.1-rc3

🧪 Testing

✅ All tests passed
✅ TypeScript checks passed
✅ Docker images built for linux/amd64, linux/arm64, linux/arm/v7

📋 Changes

See commit history for detailed changes.

Don't miss a new meshmonitor release

NewReleases is sending notifications on new releases.