Summary
sourceId is not consistently scoped across channel queries, admin routes, and notification helpers. The immediate symptom is the MQTT bridge channel list bug (non-virtual channels appearing for MQTT bridge sources), but the root cause affects at least 10 call sites across channelRoutes.ts, server.ts, and channels.ts.
The correct pattern exists in src/db/repositories/channels.ts — getAllChannels(sourceId) and getChannelById(id, sourceId) both accept an optional sourceId and add AND channels.sourceId = ? to the WHERE clause. The bugs below are call sites that have sourceId available in scope but omit it, or functions that never accepted sourceId at all.
Findings
BUG 1 — PUT /api/channels/:id response fetch (Meshtastic path)
- File:
src/server/routes/channelRoutes.ts line 523
chanSourceId is available in scope; the MeshCore branch at line 488 correctly passes it, but the Meshtastic branch does not.
- Returns the wrong source's channel in the PUT response.
- Fix:
getChannelById(channelId, chanSourceId ?? undefined)
BUG 2 — GET /api/channels/:id/export (potential PSK leak)
- File:
src/server/routes/channelRoutes.ts line 231
- No
sourceId query param is accepted or passed. In a multi-source setup could export the PSK from the wrong source.
- Fix: Accept
?sourceId= query param and pass it through.
BUG 3 — POST /api/channels/:id/import — upsert + response fetch
- File:
src/server/routes/channelRoutes.ts lines 691 and 713
importSourceId is extracted and used to resolve the manager but never passed to upsertChannel or getChannelById. Writes and reads from the wrong source row.
- Fix: Pass
importSourceId to both calls.
BUG 4 — snapshotChannelsBeforeChange() / migrateMessagesIfChannelsMoved() — CRITICAL
- File:
src/server/routes/channelRoutes.ts lines 307–328
- Both helpers call
getAllChannels() with no sourceId, fetching from ALL sources. Used before/after PUT, import, and URL-config-import routes. Cross-source false-positive channel moves can trigger migrateMessagesForChannelMoves with incorrect slot pairings, causing message-channel assignment corruption.
- Fix: Add
sourceId?: string parameter and thread it through from all callers.
BUG 5 — POST /nodes/refresh channel count response (cosmetic)
- File:
src/server/server.ts line 3340
refreshSourceId available in scope but not passed to getChannelCount(). Count reflects all sources, not the source being refreshed.
BUG 6 — POST /admin/get-channel local node path
- File:
src/server/server.ts line 4977
gcSourceId available in scope but not passed to getChannelById. Returns first source's channel regardless of which source the admin is inspecting.
BUG 7 — POST /admin/export-config local node path
- File:
src/server/server.ts line 5277
aecSourceId available in scope but not passed to getChannelById. Remote-node path is fine (fetches from device directly); local path reads from wrong source.
BUG 8 — POST /api/channels/refresh count response (cosmetic)
- File:
src/server/routes/channelRoutes.ts line 1144
chanRefreshSourceId available but not passed to getChannelCount().
BUG 9 — markChannelMessagesAsRead — no sourceId support anywhere — CRITICAL
- File:
src/server/server.ts line 2559 / src/db/repositories/notifications.ts lines 422–531
- The function has no
sourceId parameter at all. Marks messages read across ALL sources for a given channel slot. If MQTT bridge and radio source both have slot 2, marking one read marks both.
- Fix: Add
sourceId to the function signature and WHERE clause throughout the call chain.
BUG 10 — Sync repository methods have no sourceId support
- File:
src/db/repositories/channels.ts lines 320, 336, 350
getChannelByIdSync, getAllChannelsSync, and getChannelCountSync never accept or apply sourceId. Any caller using the sync path gets unscoped results.
Priority Summary
| Priority |
Bug |
File |
Lines |
Impact |
| Critical |
4 |
channelRoutes.ts |
308, 313 |
Cross-source message corruption via false-positive channel moves |
| Critical |
9 |
server.ts / notifications.ts |
2559 / 422 |
Mark-read bleeds across all sources for same slot |
| High |
2 |
channelRoutes.ts |
231 |
PSK export from wrong source |
| High |
3 |
channelRoutes.ts |
691, 713 |
Import writes to / reads from wrong source row |
| Medium |
1 |
channelRoutes.ts |
523 |
PUT response shows wrong source channel |
| Medium |
6 |
server.ts |
4977 |
Admin get-channel returns wrong source |
| Medium |
7 |
server.ts |
5277 |
Admin export-config reads wrong source |
| Medium |
10 |
channels.ts |
320, 336, 350 |
Sync path entirely unscoped |
| Low |
5, 8 |
server.ts, channelRoutes.ts |
3340, 1144 |
Cosmetic: count reflects all sources |
Authored by NodeZero 0️⃣
Summary
sourceIdis not consistently scoped across channel queries, admin routes, and notification helpers. The immediate symptom is the MQTT bridge channel list bug (non-virtual channels appearing for MQTT bridge sources), but the root cause affects at least 10 call sites acrosschannelRoutes.ts,server.ts, andchannels.ts.The correct pattern exists in
src/db/repositories/channels.ts—getAllChannels(sourceId)andgetChannelById(id, sourceId)both accept an optionalsourceIdand addAND channels.sourceId = ?to the WHERE clause. The bugs below are call sites that havesourceIdavailable in scope but omit it, or functions that never acceptedsourceIdat all.Findings
BUG 1 —
PUT /api/channels/:idresponse fetch (Meshtastic path)src/server/routes/channelRoutes.tsline 523chanSourceIdis available in scope; the MeshCore branch at line 488 correctly passes it, but the Meshtastic branch does not.getChannelById(channelId, chanSourceId ?? undefined)BUG 2 —
GET /api/channels/:id/export(potential PSK leak)src/server/routes/channelRoutes.tsline 231sourceIdquery param is accepted or passed. In a multi-source setup could export the PSK from the wrong source.?sourceId=query param and pass it through.BUG 3 —
POST /api/channels/:id/import— upsert + response fetchsrc/server/routes/channelRoutes.tslines 691 and 713importSourceIdis extracted and used to resolve the manager but never passed toupsertChannelorgetChannelById. Writes and reads from the wrong source row.importSourceIdto both calls.BUG 4 —
snapshotChannelsBeforeChange()/migrateMessagesIfChannelsMoved()— CRITICALsrc/server/routes/channelRoutes.tslines 307–328getAllChannels()with no sourceId, fetching from ALL sources. Used before/after PUT, import, and URL-config-import routes. Cross-source false-positive channel moves can triggermigrateMessagesForChannelMoveswith incorrect slot pairings, causing message-channel assignment corruption.sourceId?: stringparameter and thread it through from all callers.BUG 5 —
POST /nodes/refreshchannel count response (cosmetic)src/server/server.tsline 3340refreshSourceIdavailable in scope but not passed togetChannelCount(). Count reflects all sources, not the source being refreshed.BUG 6 —
POST /admin/get-channellocal node pathsrc/server/server.tsline 4977gcSourceIdavailable in scope but not passed togetChannelById. Returns first source's channel regardless of which source the admin is inspecting.BUG 7 —
POST /admin/export-configlocal node pathsrc/server/server.tsline 5277aecSourceIdavailable in scope but not passed togetChannelById. Remote-node path is fine (fetches from device directly); local path reads from wrong source.BUG 8 —
POST /api/channels/refreshcount response (cosmetic)src/server/routes/channelRoutes.tsline 1144chanRefreshSourceIdavailable but not passed togetChannelCount().BUG 9 —
markChannelMessagesAsRead— no sourceId support anywhere — CRITICALsrc/server/server.tsline 2559 /src/db/repositories/notifications.tslines 422–531sourceIdparameter at all. Marks messages read across ALL sources for a given channel slot. If MQTT bridge and radio source both have slot 2, marking one read marks both.sourceIdto the function signature and WHERE clause throughout the call chain.BUG 10 — Sync repository methods have no sourceId support
src/db/repositories/channels.tslines 320, 336, 350getChannelByIdSync,getAllChannelsSync, andgetChannelCountSyncnever accept or applysourceId. Any caller using the sync path gets unscoped results.Priority Summary
channelRoutes.tsserver.ts/notifications.tschannelRoutes.tschannelRoutes.tschannelRoutes.tsserver.tsserver.tschannels.tsserver.ts,channelRoutes.tsAuthored by NodeZero 0️⃣