feat(meshcore): decode unencrypted packet data in packet-log export (#3937)#3939
Conversation
…3937) The MeshCore packet-log export endpoint (GET /api/sources/:id/meshcore/packets/export) previously serialized only the raw DB row per packet, so anyone exporting had to manually decode `rawHex` for every ADVERT line even though MeshMonitor already knows how (the Packet Monitor UI's "click to decode" modal uses the same decoder). Reuse the existing isomorphic `decodeMeshCorePacket()` server-side to attach a `decoded` field to each exported JSONL line. This surfaces the full ADVERT decode (name, lat/lon, pubkey, timestamp, flags), ACK codes, and the plaintext dest/src hash prefix of encrypted messages. Encrypted message bodies remain undecoded by design. `rawHex` is preserved so nothing is lost for callers doing their own analysis. This is decode-at-export-time only — no schema/migration change and no change to what's persisted. Note: part 1 of the issue (retention >= 7 days) needs no code change; the Max age (h) filter already supports up to 720h (30 days). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AphLfgUJWaFNAgU5UXdJ4n
|
Claude finished @Yeraze's task —— View job PR Review: feat(meshcore): decode unencrypted packet data in packet-log export (#3937)
Overall AssessmentClean, well-scoped change. The implementation correctly reuses the existing isomorphic decoder rather than duplicating logic, and the backward-compatible approach (adding Code Quality
The core change is a single, well-placed line: const decoded = decodeMeshCorePacket(packet.rawHex);
res.write(JSON.stringify({ ...packet, decoded }) + '\n');This is correct. The decoder returns Minor: This is a pre-existing issue (not introduced by this PR), but worth noting: if Potential BugsNone introduced by this PR. The decoder ( One subtle correctness note: PerformanceThe decode runs synchronously per packet in the export loop. For the default cap of 1,000 packets this is negligible. For very large exports (e.g., SecurityNo new attack surface. The decoder is purely a bytes-to-struct operation on data already stored in the DB, uses no eval/dynamic dispatch, and cannot make network calls. The export endpoint's existing auth ( Test CoverageTwo new test cases were added. Coverage is solid for the happy path:
Gap: no test for Gap: the "short/undecodable" test (line 2384) uses SummaryRecommend merging. The change is minimal, correct, backward-compatible, and well-tested. The one suggested improvement (a null- |
Closes #3937
Summary
Issue #3937 has two parts:
168gives a 7-day window. (Raise Max count alongside it for long windows, since it trims per-source regardless of age.)The gap
GET /api/sources/:id/meshcore/packets/exportpreviously serialized only the raw DB row per packet (rawHex,payloadType,routeType, SNR/RSSI, etc.). Consumers had to manually decoderawHexfor every ADVERT line themselves, even though MeshMonitor already ships a full, dependency-free decoder (src/utils/meshcorePacketDecode.ts) that powers the Packet Monitor UI's "click to decode" modal.Change
Reuse the existing isomorphic
decodeMeshCorePacket()server-side in the export route to attach adecodedfield to each exported JSONL line:payloadType === 0x04: name, lat/lon, pubkey, timestamp, signature, flags.rawHexand all existing raw fields are preserved, so nothing is lost for callers doing their own analysis.Decode-at-export-time only — no schema/migration change, no change to what's persisted. Decoding never throws; parse issues surface as
null/ a.errorsarray.Testing
meshcoreRoutes.test.ts): one asserts a full ADVERT line is decoded (nameRepeater-1, lat 37.5 / lon -122.25, pubkey) withrawHexpreserved; one asserts short/encrypted rows still get adecodedheader block with no advert.tsc -p tsconfig.server.json --noEmit: no new errors from this change (only pre-existingTelemetryChart.tsxfrontend errors present onmain).🤖 Generated with Claude Code
https://claude.ai/code/session_01AphLfgUJWaFNAgU5UXdJ4n