fix(prefs): skip channels with empty secret in loadChannels

An all-zero secret in /channels2 means the entry is uninitialised or the
file format was corrupted by a previous firmware (e.g. different on-disk
layout from an older fork). Loading such a channel makes findChannelIdx()
match the wrong slot for incoming messages — they end up associated with
the bogus channel index and never display, even when the companion app
receives them fine over BLE.

Skip empty-secret entries during load and log how many were dropped.
Also defensively null-terminate the loaded name so callers can treat it
as a C string regardless of how the file was written.

Reported via user feedback: "only public visible, hashtag channels not;
public was empty; phone could read messages; works after wipe".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-29 19:56:25 +02:00
parent 8cfe4c3ac8
commit cb37d23eb0

View File

@@ -518,6 +518,7 @@ void DataStore::loadChannels(DataStoreHost* host) {
if (file) {
bool full = false;
uint8_t channel_idx = 0;
uint8_t skipped = 0;
while (!full) {
ChannelDetails ch;
uint8_t unused[4];
@@ -528,6 +529,23 @@ void DataStore::loadChannels(DataStoreHost* host) {
if (!success) break; // EOF
// Sanity check: an all-zero secret means the entry is uninitialised
// or the file format was corrupted by a previous firmware (different
// layout). Loading such a channel makes findChannelIdx() match the
// wrong slot for incoming messages — drop it. The companion app can
// re-sync the channel afterwards.
bool secret_empty = true;
for (int b = 0; b < 32; b++) {
if (ch.channel.secret[b] != 0) { secret_empty = false; break; }
}
if (secret_empty) {
skipped++;
continue;
}
// Defensive: ensure name is null-terminated so callers can treat it
// as a C string regardless of how the file was written.
ch.name[31] = '\0';
if (host->onChannelLoaded(channel_idx, ch)) {
channel_idx++;
} else {
@@ -535,6 +553,10 @@ void DataStore::loadChannels(DataStoreHost* host) {
}
}
file.close();
if (skipped > 0) {
MESH_DEBUG_PRINTLN("loadChannels: skipped %u corrupted/empty channel entr%s",
(unsigned)skipped, skipped == 1 ? "y" : "ies");
}
}
}