From 8e9df0548b5ed3b68c07a661dbd7c29e8c7d60c3 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 3 Oct 2025 20:02:09 -0500 Subject: [PATCH 01/10] Null out user.id except for sending to phone --- src/mesh/NodeDB.cpp | 20 ++++++++++++++++++++ src/modules/AdminModule.cpp | 7 +++---- src/modules/NodeInfoModule.cpp | 21 +++++++++++++++++---- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a32ee37f99..a5a3b02610 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -256,6 +256,8 @@ NodeDB::NodeDB() owner.role = config.device.role; // Ensure macaddr is set to our macaddr as it will be copied in our info below memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); + // Ensure owner.id is always derived from the node number + snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); if (!config.has_security) { config.has_security = true; @@ -1179,6 +1181,19 @@ void NodeDB::loadFromDisk() meshNodes = &nodeDatabase.nodes; numMeshNodes = nodeDatabase.nodes.size(); LOG_INFO("Loaded saved nodedatabase version %d, with nodes count: %d", nodeDatabase.version, nodeDatabase.nodes.size()); + + // Ensure all loaded nodes have properly derived user.id values + for (int i = 0; i < numMeshNodes; i++) { + meshtastic_NodeInfoLite *node = &meshNodes->at(i); + if (node->has_user) { + // Force user.id to be derived from node number for consistency + char correctId[10]; + snprintf(correctId, sizeof(correctId), "!%08x", node->num); + // We can't directly modify the id in UserLite, so we use ConvertToUser and back + meshtastic_User fullUser = TypeConversions::ConvertToUser(node->num, node->user); + node->user = TypeConversions::ConvertToUserLite(fullUser); + } + } } if (numMeshNodes > MAX_NUM_NODES) { @@ -1602,6 +1617,8 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) } info->num = contact.node_num; info->has_user = true; + // Ensure user.id is derived from node number + snprintf(contact.user.id, sizeof(contact.user.id), "!%08x", contact.node_num); info->user = TypeConversions::ConvertToUserLite(contact.user); if (contact.should_ignore) { // If should_ignore is set, @@ -1666,6 +1683,9 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde } #endif + // Always ensure user.id is derived from nodeId, regardless of what was received + snprintf(p.id, sizeof(p.id), "!%08x", nodeId); + // Both of info->user and p start as filled with zero so I think this is okay auto lite = TypeConversions::ConvertToUserLite(p); bool changed = memcmp(&info->user, &lite, sizeof(info->user)) || (info->channel != channelIndex); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 7544db1218..e7aa3a027c 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -554,10 +554,9 @@ void AdminModule::handleSetOwner(const meshtastic_User &o) changed |= strcmp(owner.short_name, o.short_name); strncpy(owner.short_name, o.short_name, sizeof(owner.short_name)); } - if (*o.id) { - changed |= strcmp(owner.id, o.id); - strncpy(owner.id, o.id, sizeof(owner.id)); - } + // User id is not settable + owner.id[0] = '\0'; + if (owner.is_licensed != o.is_licensed) { changed = 1; owner.is_licensed = o.is_licensed; diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 2c3c274d22..30dae8133f 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -23,16 +23,26 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes return true; } - // Coerce user.id to be derived from the node number - snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp)); + // Null out user.id so we can derive it from node number later + p.id[0] = '\0'; bool hasChanged = nodeDB->updateUser(getFrom(&mp), p, mp.channel); bool wasBroadcast = isBroadcast(mp.to); + // LOG_DEBUG("did encode"); // if user has changed while packet was not for us, inform phone - if (hasChanged && !wasBroadcast && !isToUs(&mp)) - service->sendToPhone(packetPool.allocCopy(mp)); + if (hasChanged && !wasBroadcast && !isToUs(&mp)) { + auto packetCopy = packetPool.allocCopy(mp); // Keep a copy of the packet for later analysis + + // Re-encode the user protobuf, as we have stripped out the user.id + packetCopy->decoded.payload.size = pb_encode_to_bytes( + packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p); + + // Set user.id back to being based on the node number for the phone + snprintf(p.id, sizeof(p.id), "!%08x", mp.from); + service->sendToPhone(packetCopy); + } // LOG_DEBUG("did handleReceived"); return false; // Let others look at this message also if they want @@ -95,6 +105,9 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() u.public_key.size = 0; } + // Clear the user.id field since it should be derived from node number on the receiving end + u.id[0] = '\0'; + LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name); lastSentToMesh = millis(); return allocDataProtobuf(u); From 95c9a7fbd4124480cc81ffee302739e73d14b599 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 3 Oct 2025 20:05:57 -0500 Subject: [PATCH 02/10] Fix --- src/modules/AdminModule.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index e7aa3a027c..9af5f669dd 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -554,8 +554,7 @@ void AdminModule::handleSetOwner(const meshtastic_User &o) changed |= strcmp(owner.short_name, o.short_name); strncpy(owner.short_name, o.short_name, sizeof(owner.short_name)); } - // User id is not settable - owner.id[0] = '\0'; + snprintf(owner.id, sizeof(owner.id), "!%08x", nodeDB->getNodeNum()); if (owner.is_licensed != o.is_licensed) { changed = 1; From 02c98d2a0c2164863fb6154b142459ef045b806d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 3 Oct 2025 20:52:39 -0500 Subject: [PATCH 03/10] Update src/modules/NodeInfoModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/modules/NodeInfoModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 30dae8133f..da5042568a 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -40,7 +40,7 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p); // Set user.id back to being based on the node number for the phone - snprintf(p.id, sizeof(p.id), "!%08x", mp.from); + snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp)); service->sendToPhone(packetCopy); } From 08015e0a0ca123311dfbcd29646c27963527d588 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 3 Oct 2025 20:54:47 -0500 Subject: [PATCH 04/10] Copilot garbage --- src/mesh/NodeDB.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index a5a3b02610..58d3bd0036 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1181,19 +1181,6 @@ void NodeDB::loadFromDisk() meshNodes = &nodeDatabase.nodes; numMeshNodes = nodeDatabase.nodes.size(); LOG_INFO("Loaded saved nodedatabase version %d, with nodes count: %d", nodeDatabase.version, nodeDatabase.nodes.size()); - - // Ensure all loaded nodes have properly derived user.id values - for (int i = 0; i < numMeshNodes; i++) { - meshtastic_NodeInfoLite *node = &meshNodes->at(i); - if (node->has_user) { - // Force user.id to be derived from node number for consistency - char correctId[10]; - snprintf(correctId, sizeof(correctId), "!%08x", node->num); - // We can't directly modify the id in UserLite, so we use ConvertToUser and back - meshtastic_User fullUser = TypeConversions::ConvertToUser(node->num, node->user); - node->user = TypeConversions::ConvertToUserLite(fullUser); - } - } } if (numMeshNodes > MAX_NUM_NODES) { From a4104f5e5a743e7d13051ead11d7e4bfc1f4968c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 05:49:45 -0500 Subject: [PATCH 05/10] This is unnecessary, because we don't stored user.id on userlite --- src/mesh/NodeDB.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 615a641162..e03343065b 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1631,8 +1631,6 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact) } info->num = contact.node_num; info->has_user = true; - // Ensure user.id is derived from node number - snprintf(contact.user.id, sizeof(contact.user.id), "!%08x", contact.node_num); info->user = TypeConversions::ConvertToUserLite(contact.user); if (contact.should_ignore) { // If should_ignore is set, From 9f80d1345cbbc455fa0285258c1c86d2d108d73c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:03:31 -0500 Subject: [PATCH 06/10] Don't need this --- src/modules/NodeInfoModule.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index da5042568a..3be7560976 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -23,8 +23,8 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes return true; } - // Null out user.id so we can derive it from node number later - p.id[0] = '\0'; + // Coerce user.id to be derived from the node number + snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp)); bool hasChanged = nodeDB->updateUser(getFrom(&mp), p, mp.channel); @@ -39,8 +39,6 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes packetCopy->decoded.payload.size = pb_encode_to_bytes( packetCopy->decoded.payload.bytes, sizeof(packetCopy->decoded.payload.bytes), &meshtastic_User_msg, &p); - // Set user.id back to being based on the node number for the phone - snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp)); service->sendToPhone(packetCopy); } From bb19c2dafe0930d39dfaa848af55dfdcdc31b9d4 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:05:16 -0500 Subject: [PATCH 07/10] Fix warning --- src/mesh/NodeDB.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index e03343065b..e3240462df 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -56,10 +56,6 @@ #include #endif -// stringify -#define xstr(s) str(s) -#define str(s) #s - NodeDB *nodeDB = nullptr; // we have plenty of ram so statically alloc this tempbuf (for now) From aa3b49eda9155a6c6c92c743f52cd0120a6fb72d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:16:54 -0500 Subject: [PATCH 08/10] Just alter the protobuf --- src/modules/NodeInfoModule.cpp | 7 ++++++- src/modules/NodeInfoModule.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 3be7560976..4c06d7fa8b 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -46,6 +46,12 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes return false; // Let others look at this message also if they want } +void NodeInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_User *p) +{ + // Coerce user.id to be derived from the node number + snprintf(p->id, sizeof(p->id), "!%08x", getFrom(&mp)); +} + void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t channel, bool _shorterTimeout) { // cancel any not yet sent (now stale) position packets @@ -105,7 +111,6 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() // Clear the user.id field since it should be derived from node number on the receiving end u.id[0] = '\0'; - LOG_INFO("Send owner %s/%s/%s", u.id, u.long_name, u.short_name); lastSentToMesh = millis(); return allocDataProtobuf(u); diff --git a/src/modules/NodeInfoModule.h b/src/modules/NodeInfoModule.h index c1fb9cccec..572b817007 100644 --- a/src/modules/NodeInfoModule.h +++ b/src/modules/NodeInfoModule.h @@ -30,6 +30,9 @@ class NodeInfoModule : public ProtobufModule, private concurren */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *p) override; + /** Called to alter received User protobuf */ + virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_User *p) override; + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ virtual meshtastic_MeshPacket *allocReply() override; From 8963e0299f8a9e7f88dff35b32e5bb67b4546e2b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:31:56 -0500 Subject: [PATCH 09/10] Alter protobuf doesn't do anything with the altered data, so let's re-encode it --- src/modules/NodeInfoModule.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 4c06d7fa8b..9b94b39337 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -50,6 +50,10 @@ void NodeInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic { // Coerce user.id to be derived from the node number snprintf(p->id, sizeof(p->id), "!%08x", getFrom(&mp)); + + // Re-encode the altered protobuf back into the packet + mp.decoded.payload.size = + pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_User_msg, p); } void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t channel, bool _shorterTimeout) From 7deb4e800b4a9a896ae00318f2a7010a374cc230 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 4 Oct 2025 06:42:17 -0500 Subject: [PATCH 10/10] Check inputbroker before access --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index bca2da2cb7..b0f086f140 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1601,7 +1601,8 @@ void loop() service->loop(); #if !MESHTASTIC_EXCLUDE_INPUTBROKER && defined(HAS_FREE_RTOS) - inputBroker->processInputEventQueue(); + if (inputBroker) + inputBroker->processInputEventQueue(); #endif #if defined(LGFX_SDL) if (screen) {