87 Commits

Author SHA1 Message Date
l5y 2479a6554f fix: UDP-transport hardening, bridge tracker coverage, CI repairs; release 0.7.2 (#840)
* fix: UDP-transport hardening, bridge tracker coverage, CI repairs; release 0.7.2

* fix: UDP-transport hardening, bridge tracker coverage, CI repairs; release 0.7.2
2026-07-06 00:30:52 +02:00
TJ Paulson df201f3ee4 fix: security review — dashboard XSS, private-mode federation gap, Matrix bridge resilience (#839)
* fix(web): escape untrusted mesh fields in dashboard to close DOM XSS

Security review found user-controlled mesh data reaching innerHTML unescaped
(upstream-originating; worth a PR back to l5yth/potato-mesh):

- High: channel_name was interpolated raw by formatChatChannelTag and rendered
  via innerHTML on the node-detail page and map overlays, so a crafted channel
  name (any radio can set one) executed script for every viewer. Now escaped
  with the canonical escapeHtml.
- Defense-in-depth: node_id, role, and hw_model in the node table are now
  escaped for consistency with sibling cells.

Regression test added for the channel-name escape. Full JS suite: 1448 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(web): gate POST /api/instances by federation mode + hardening

Security review findings in the Sinatra app (upstream-originating; worth a PR
back to l5yth/potato-mesh):

- High: POST /api/instances performed outbound federation fetches and DB writes
  with no federation/private guard, so a PRIVATE=1 or FEDERATION=0 node still
  acted on unsolicited signed announcements. Added `halt 404 unless
  federation_enabled?`, mirroring the existing GET /api/instances guard.
- Low: the JSON-LD <script> block now escapes </script> breakout characters.
- Low: federation peer fetches now enforce a max response size
  (REMOTE_INSTANCE_MAX_RESPONSE_BYTES, default 8 MiB) to bound memory.

Regression spec added for the federation-gate (private + FEDERATION=0 cases).

NOTE: rspec could not be run locally (this host has only Ruby 2.6; the project
needs >=3.0 and no Docker was available). Changes are `ruby -c` syntax-checked
and reviewed against the mirrored guard; the ruby.yml CI workflow must confirm
the spec on push/PR before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(matrix): stop silent message loss + add HTTP timeouts + log reg failures

Security/resilience review of the Matrix bridge (upstream-originating; worth a
PR back to l5yth/potato-mesh):

- High: within a poll batch, a later message that forwarded successfully
  advanced the in-memory rx_time watermark past an EARLIER message that failed,
  so the failed message was never refetched -> silent permanent loss. poll_once
  now breaks at the first failure, committing only the contiguous successful
  prefix; the failed message and everything after it are retried in order next
  poll (no reordering, no duplicates). Regression test added and proven to bite.
- High: the shared reqwest client had no timeouts, so a hung homeserver/API
  stalled the single-threaded poll loop (and startup health checks) forever.
  Added timeout(30s) + connect_timeout(10s).
- Medium: ensure_user_registered swallowed all non-success responses silently;
  it now warns (status + body) on anything other than the expected
  already-registered case, so a bad as_token is diagnosable.

cargo test: 118 passed; cargo fmt clean. Tradeoff: a permanently-failing
message now blocks its batch (retried each poll) rather than being lost -- safer
than silent loss; a skip-after-N/dead-letter follow-up is possible if needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: address Copilot review on the security PR (Matrix errcode + spec hygiene)

- matrix.rs: ensure_user_registered now treats only the specific M_USER_IN_USE
  errcode as "already registered", instead of any 400 Bad Request, so real 400
  failures (malformed request, config issues) reach the diagnostic warn branch.
  Updated the M_USER_IN_USE test to send the errcode body and added a test that
  a non-M_USER_IN_USE 400 is not suppressed. cargo test: 119 passing.
- app_spec.rb: the private-mode POST /api/instances example now restores
  ENV["PRIVATE"] via an around/ensure block (mirroring the FEDERATION pattern),
  so private mode can't leak into later specs and cause order-dependent failures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: implement Copilot follow-ups — streaming size cap + bounded skip

- instance_fetcher.rb: perform_single_http_request now uses the block form of
  Net::HTTP#request + response.read_body to enforce the response-size cap
  INCREMENTALLY, aborting as soon as the limit is exceeded, instead of letting
  the non-block form buffer the whole body into memory first. Updated the two
  federation_spec mocks to the block/streaming form and added a size-cap test.
- main.rs (Matrix bridge): a permanently-failing ("poison") message no longer
  blocks the batch forever. Consecutive per-message failures are counted
  in-memory; after MAX_FORWARD_ATTEMPTS (5) the message is skipped (advanced
  past, with a warning) so later messages make progress. Transient failures
  still stop-and-retry in order (no silent loss, no reordering). Added a
  skip-after-N regression test; the original watermark test still passes.
  cargo test: 120 passing, cargo fmt clean.

Ruby: instance_fetcher.rb is `ruby -c` clean; the spec exercises the new paths
but rspec/`ruby -c` can't run locally (Ruby 2.6 here can't parse the repo's
3.1+ syntax) — the ruby.yml CI is the gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(web): fix private-mode /api/instances spec to actually enable private mode

Running the suite locally (Ruby 4.0) revealed the private-mode POST /api/instances
example never entered private mode: the top-level `before` hook deletes
ENV["PRIVATE"] before each example, so toggling it (even via an around block)
had no effect and the request returned 201 instead of 404.

Switch to stubbing PotatoMesh::Config.private_mode_enabled? => true, the pattern
the rest of the suite uses for private-mode cases. This makes the test actually
exercise the guard AND removes the ENV manipulation entirely (so there is no
cross-spec ENV leak to worry about). Full web suite: 1470 examples, 0 failures;
rufo clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 22:27:37 +02:00
l5y 8ed15f1142 web: initial-load module-graph waterfall (#832)
* web: initial-load module-graph waterfall

* web: prefetch initial API data on cold load (faster first paint)

Second phase of the initial-load fix (after the module-graph preload in
8915f8c). Even with the graph preloaded, the first /api/* fetch waited for the
~806KB bundle to download, parse, and boot. An early <script type="module"
async> boot module (main/boot-prefetch.js) now fires the first-load (since=0)
requests in parallel with the module graph (at priority:'high') and stashes the
in-flight Response promises on window.__PM_BOOT__; refresh() consumes them on its
first cold refresh via a new responsePromise option on the data-fetchers instead
of issuing its own requests.

Cold loads only: a synchronous localStorage marker (pm:cache-present, maintained
by the cache write-back / clear / disable paths) suppresses the prefetch on warm
revisits, leaving the FC2 seed-then-delta path untouched. Message endpoints are
skipped in private mode (data-pm-chat="false"), mirroring the /api/messages 404
(Invariant II / PS6). Pure pre-warm: an absent or rejected prefetch re-fetches,
so it is never load-bearing (FC7).

Read-side only; no API/DB/ingestor change, no new dependency. Adds ACCEPTANCE
EF-A1/EF-A2/EF-R1; 100% line/branch/func coverage on the new module (lcov);
rspec + npm test green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 14:50:33 +02:00
l5y b5d9249918 web: change tiles to carto (#831)
* web: change tiles to carto

* web: change tiles to carto
2026-06-28 20:59:52 +02:00
l5y 1804a8a75e web: add visual feedback to pubsub events (#824) 2026-06-24 20:34:35 +02:00
l5y 3790686ab2 web: version JS/CSS assets to bust stale browser caches (#815) 2026-06-23 21:23:35 +02:00
l5y 43a5724b7f web: add seo improvements (#771)
* web: add seo improvements

* web: address review comments

* web: address review comments
2026-04-29 10:33:33 +02:00
l5y c08b3f2c2d web: restore refresh and protocol buttons (#742)
* web: restore refresh and protocol buttons

* web: restore refresh and protocol buttons

* web: restore refresh and protocol buttons

* web: address review comments
2026-04-14 16:54:57 +02:00
l5y b951dbffeb web: per protocol active node counts (#735)
* web: per protocol active node counts

* web: address review comments
2026-04-13 18:26:16 +02:00
l5y 81e588e44c web: add markdown static pages (#723)
* web: add markdown static pages

* web: add tests and docker

* web: improve wording and configs

* web: add tests

* web: address review comments

* web: address review comments

* Potential fix for pull request finding 'CodeQL / Incomplete multi-character sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* web: address review comments

* web: address review comments

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-04-08 16:42:13 +02:00
l5y 083de6418f web: fix federation for multi protocol (#722)
* web: fix federation for multi protocol

* web: fix short name emojis

* web: address review comments

* ci: fix the codeql gap

* ci: fix the codeql gap

* ci: fix the codeql gap

* ci: remove swift
2026-04-08 14:36:43 +02:00
l5y 4d38ddd341 web: facelift (#716)
* web: facelift

* web: facelift

* web: facelift

* web: address review comments

* web: address review comments

* web: address review comments

* web: address review comments

* web: address review comments

* web: address review comments

* web: more css magic

* web: link parsing for chat contact

* web: remove one-letter fallback for shortnames

* Potential fix for pull request finding 'CodeQL / Incomplete multi-character sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* web: fix fallback for shortnames

* web: address review comments

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-04-07 21:38:43 +02:00
l5y 06530f36ff web: add proper short names for meshcore companions (#693)
* web: add proper short names for meshcore companions

* web: address review comments
2026-04-05 09:01:43 +02:00
l5y 3cfa0db7e6 web: distinguish meshcore from meshtastic in frontend (#688)
* web: distinguish meshcore from meshtastic in frontend

* fix mark_packet_seen bug

* web: distinguish meshcore from meshtastic in frontend

* address review comments

* address review comments

* address review comments
2026-04-04 17:14:16 +02:00
l5y 108573b100 web: add announcement banner (#609)
* web: add announcement banner

* web: cover missing unit test vectors
2026-01-08 21:17:59 +01:00
l5y f5f2e977a1 web: collapse federation map ledgend (#604)
* web: collapse federation map ledgend

* web: cover missing unit test vectors
2026-01-06 17:31:20 +01:00
l5y 7f40abf92a web: establish menu structure (#597)
* web: establish menu structure

* web: cover missing unit test vectors

* web: fix tests
2026-01-05 21:18:51 +01:00
l5y 6c711f80b4 web: hide legend by default (#582)
* web: hide legend my default

* web: run rufo
2025-12-31 12:42:53 +01:00
l5y baf6ffff0b web: improve instances map and table view (#546)
* web: improve instances map and table view

* web: address review comments

* run rufo
2025-12-14 14:35:55 +01:00
l5y 844204f64d web: fix traces rendering (#535)
* web: fix traces rendering

* web: remove icon shortcuts

* web: further refine the trace routes
2025-12-08 19:48:33 +01:00
l5y 8181fc8e03 web: further refine the federation page (#534)
* web: further refine the federation page

* web: address review comments

* web: address review comments
2025-12-04 13:31:23 +01:00
apo-mak 5be2ac417a Add Federation Map (#532)
* Add Federation Map

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: l5y <220195275+l5yth@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 12:24:54 +01:00
l5y eaa691808a web: fix favicon (#515) 2025-11-25 22:26:30 +01:00
l5y eab6af414f add frequency and preset to node table (#472) 2025-11-19 17:39:15 +01:00
l5y b298f2f22c env: add map zoom (#454)
* chore: bump version to 0.5.5 everywhere

* add MAP_ZOOM varibale

* run black
2025-11-16 12:57:47 +01:00
l5y 9304a99745 charts: render aggregated telemetry charts for all nodes (#453) 2025-11-15 17:09:55 +01:00
l5y 4a03e17886 nodes: render charts detail pages as overlay (#452) 2025-11-15 12:13:06 +01:00
l5y 05efbc5f20 Refine node detail view layout (#442)
* Refine node detail view layout

* Refine node detail controls and formatting

* Improve node detail neighbor roles and message metadata

* Fix node detail neighbor metadata hydration
2025-11-13 19:59:07 +01:00
l5y cb843d5774 Add node detail route and page (#441) 2025-11-13 17:19:20 +01:00
l5y 8823b7cb48 Add standalone full-screen map, chat, and nodes views (#429)
* Add dedicated full-screen dashboard views

* Simplify full-screen routes layout

* Restore refresh controls on full-screen views

* Polish standalone view layout

* Streamline standalone layouts
2025-11-12 11:38:26 +01:00
l5y 2bb8e3fd66 Chore: update license headers (#424) 2025-11-08 10:41:57 +01:00
l5y 32d9da2865 Add instance selector dropdown for federation deployments (#382)
* Add instance selector for federation regions

* Avoid HTML insertion when seeding instance selector
2025-10-18 10:53:26 +02:00
l5y cc8fec6d05 Align theme and info controls (#371)
* Align theme and info controls

* design tweaks
2025-10-17 19:27:14 +00:00
l5y b7ef0bbfcd Adjust node table columns responsively (#332) 2025-10-14 14:59:47 +02:00
l5y ffad84f18a Ensure frontend reports git-aware version strings (#321)
* Ensure frontend reports git-aware version strings

* Keep footer fixed across viewport widths
2025-10-13 16:26:57 +02:00
l5y 40b6eda096 Refine stacked short info overlays on the map (#319)
* Refine map overlays to use stacked short info panels

* Allow stacked overlays to pass neighbor clicks
2025-10-13 14:53:43 +02:00
l5y dee6ad7e4a Refine environment configuration defaults (#318) 2025-10-13 14:06:14 +02:00
l5y 3cfbffc155 Add fullscreen toggle to map view (#263)
* Add fullscreen mode controls for map

* Improve fullscreen map scaling and control icon

* Improve fullscreen map sizing and icon
2025-10-07 15:53:18 +02:00
l5y a592b655c4 Force dark theme default based on sanitized cookie (#252)
* Ensure dark theme defaults cleanly on initial load

* Ensure form controls respond to theme
2025-10-07 09:00:55 +02:00
l5y 64f8862676 Refactor front-end assets into external modules (#245)
* Refactor front-end assets into external modules

* Restore chat flag inline script

* Declare legend toggle control variable

* Remove dynamic background generation

* Restore background script with theme-based color

* run rufo
2025-10-07 08:33:06 +02:00
l5y c9bba25e5a Add comprehensive inline documentation (#240) 2025-10-07 00:01:31 +02:00
l5y 5a47a8f8e4 Reformat neighbor overlay details (#237) 2025-10-06 08:08:24 +02:00
l5y c13f3c913f Add neighbor lines toggle to map legend (#236) 2025-10-06 08:05:44 +02:00
l5y 2e9b54b6cf Hide Air Util Tx column on mobile (#235) 2025-10-06 08:04:07 +02:00
l5y 7e844be627 Add overlay for clickable neighbor links on map (#234)
* Add overlay for clickable neighbor links on map

* Fix neighbor overlays and include SNR details

* Prevent map neighbor overlay clicks from closing immediately
2025-10-06 07:41:11 +02:00
l5y b37e55c29a Hide humidity and pressure on mobile (#232) 2025-10-06 06:34:48 +02:00
l5y 332ba044f2 Remove last position timestamp from map info overlay (#233) 2025-10-06 06:34:37 +02:00
l5y 09a2d849ec Improve live node positions and expose precision metadata (#231)
* Fetch latest node positions and precision metadata

* Stop showing position source and precision in UI

* Guard node positions against stale merges
2025-10-05 23:08:57 +02:00
l5y a3fb9b0d5c Show neighbor short names in info overlays (#228)
* Show neighbor short names in info overlays

* Adjust neighbor info placement
2025-10-05 22:04:29 +02:00
l5y 192978acf9 Add telemetry environmental data to node UI (#227) 2025-10-05 21:49:28 +02:00