Skip to content

Commit 68e842a

Browse files
Yerazeclaude
andauthored
fix: channel database no longer shadows device channels with same PSK (#2415)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 48f72ec commit 68e842a

File tree

1 file changed

+46
-15
lines changed

1 file changed

+46
-15
lines changed

src/server/meshtasticManager.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3906,8 +3906,22 @@ class MeshtasticManager {
39063906
if (isDirectMessage) {
39073907
channelIndex = -1;
39083908
} else if (context?.decryptedBy === 'server' && context?.decryptedChannelId !== undefined) {
3909-
// Use Channel Database ID + offset for server-decrypted messages
3910-
channelIndex = CHANNEL_DB_OFFSET + context.decryptedChannelId;
3909+
// Check if the database channel's PSK matches a device channel — if so, prefer the device channel
3910+
// This prevents database channels from "shadowing" device channels with the same key (#2375, #2413)
3911+
const dbChannel = await databaseService.channelDatabase.getByIdAsync(context.decryptedChannelId);
3912+
const deviceChannels = await databaseService.channels.getAllChannels();
3913+
const matchingDeviceChannel = dbChannel?.psk
3914+
? deviceChannels.find(dc => dc.psk === dbChannel.psk && dc.role !== 0)
3915+
: null;
3916+
3917+
if (matchingDeviceChannel) {
3918+
// Device channel has the same PSK — use device channel slot instead of database channel
3919+
channelIndex = matchingDeviceChannel.id;
3920+
logger.debug(`📡 Server-decrypted message matches device channel ${matchingDeviceChannel.id} ("${matchingDeviceChannel.name}") — using device channel instead of database channel`);
3921+
} else {
3922+
// No matching device channel — use Channel Database ID + offset
3923+
channelIndex = CHANNEL_DB_OFFSET + context.decryptedChannelId;
3924+
}
39113925
} else {
39123926
channelIndex = meshPacket.channel !== undefined ? meshPacket.channel : 0;
39133927
}
@@ -3974,22 +3988,39 @@ class MeshtasticManager {
39743988
logger.debug(`💾 Saved channel message from ${message.fromNodeId} on channel ${channelIndex}: "${messageText.substring(0, 30)}..." (replyId: ${message.replyId})`);
39753989
}
39763990

3977-
// Dual-channel insertion: if server-decrypted and the packet has a radio channel,
3978-
// also insert a copy in the radio channel so both views show the message (#2375)
3979-
if (!isDirectMessage && context?.decryptedBy === 'server' && meshPacket.channel !== undefined) {
3980-
const radioChannelIndex = meshPacket.channel;
3981-
const radioChannel = await databaseService.channels.getChannelById(radioChannelIndex);
3982-
if (radioChannel) {
3983-
const radioCopy: TextMessage = {
3991+
// Dual-channel insertion for server-decrypted messages (#2375, #2413)
3992+
// Messages should appear in BOTH the device channel and database channel views
3993+
if (!isDirectMessage && context?.decryptedBy === 'server' && context?.decryptedChannelId !== undefined) {
3994+
if (channelIndex < CHANNEL_DB_OFFSET) {
3995+
// Primary went to device channel — also insert into database channel
3996+
const dbChannelIndex = CHANNEL_DB_OFFSET + context.decryptedChannelId;
3997+
const dbCopy: TextMessage = {
39843998
...message,
3985-
id: `${message.id}_radio`,
3986-
channel: radioChannelIndex,
3999+
id: `${message.id}_dbchan`,
4000+
channel: dbChannelIndex,
39874001
decryptedBy: 'server',
39884002
};
3989-
const radioInserted = await databaseService.messages.insertMessage(radioCopy);
3990-
if (radioInserted) {
3991-
dataEventEmitter.emitNewMessage(radioCopy as any);
3992-
logger.debug(`💾 Also saved to radio channel ${radioChannelIndex} ("${radioChannel.name}")`);
4003+
const dbInserted = await databaseService.messages.insertMessage(dbCopy);
4004+
if (dbInserted) {
4005+
dataEventEmitter.emitNewMessage(dbCopy as any);
4006+
logger.debug(`💾 Also saved to database channel ${dbChannelIndex}`);
4007+
}
4008+
} else if (meshPacket.channel !== undefined) {
4009+
// Primary went to database channel — also insert into radio channel if it exists
4010+
const radioChannelIndex = meshPacket.channel;
4011+
const radioChannel = await databaseService.channels.getChannelById(radioChannelIndex);
4012+
if (radioChannel) {
4013+
const radioCopy: TextMessage = {
4014+
...message,
4015+
id: `${message.id}_radio`,
4016+
channel: radioChannelIndex,
4017+
decryptedBy: 'server',
4018+
};
4019+
const radioInserted = await databaseService.messages.insertMessage(radioCopy);
4020+
if (radioInserted) {
4021+
dataEventEmitter.emitNewMessage(radioCopy as any);
4022+
logger.debug(`💾 Also saved to radio channel ${radioChannelIndex} ("${radioChannel.name}")`);
4023+
}
39934024
}
39944025
}
39954026
}

0 commit comments

Comments
 (0)