From cb37d23eb077e53c9d9606a56e0d6abb1a5f98cc Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Fri, 29 May 2026 19:56:25 +0200 Subject: [PATCH] fix(prefs): skip channels with empty secret in loadChannels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- examples/companion_radio/DataStore.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 0f86c1b7..bea9a0a0 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -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"); + } } }