@@ -992,6 +992,17 @@ class MeshService : Service() {
992992 sessionPasskey = a.sessionPasskey
993993 }
994994
995+ /* *
996+ * Check if a User is a default/placeholder from firmware (node was evicted and re-created) and whether we should
997+ * preserve existing user data instead of overwriting it.
998+ */
999+ private fun shouldPreserveExistingUser (existing : MeshProtos .User , incoming : MeshProtos .User ): Boolean {
1000+ val isDefaultName = incoming.longName.matches(Regex (" ^Meshtastic [0-9a-fA-F]{4}$" ))
1001+ val isDefaultHwModel = incoming.hwModel == MeshProtos .HardwareModel .UNSET
1002+ val hasExistingUser = existing.id.isNotEmpty() && existing.hwModel != MeshProtos .HardwareModel .UNSET
1003+ return hasExistingUser && isDefaultName && isDefaultHwModel
1004+ }
1005+
9951006 private fun handleSharedContactImport (contact : AdminProtos .SharedContact ) {
9961007 handleReceivedUser(contact.nodeNum, contact.user, manuallyVerified = true )
9971008 }
@@ -1006,22 +1017,37 @@ class MeshService : Service() {
10061017 updateNodeInfo(fromNum) {
10071018 val newNode = (it.isUnknownUser && p.hwModel != MeshProtos .HardwareModel .UNSET )
10081019
1009- val keyMatch = ! it.hasPKC || it.user.publicKey == p.publicKey
1010- it.user =
1011- if (keyMatch) {
1012- p
1013- } else {
1014- p.copy {
1015- Timber .w(" Public key mismatch from $longName ($shortName )" )
1016- publicKey = NodeEntity .ERROR_BYTE_STRING
1020+ // Check if this is a default/unknown user from firmware (node was evicted and re-created)
1021+ val shouldPreserve = shouldPreserveExistingUser(it.user, p)
1022+
1023+ if (shouldPreserve) {
1024+ // Firmware sent us a placeholder - keep all our existing user data
1025+ Timber .d(
1026+ " Preserving existing user data for node $fromNum : " +
1027+ " kept='${it.user.longName} ' (hwModel=${it.user.hwModel} ), " +
1028+ " skipped default='${p.longName} ' (hwModel=UNSET)" ,
1029+ )
1030+ // Still update channel and verification status
1031+ it.channel = channel
1032+ it.manuallyVerified = manuallyVerified
1033+ } else {
1034+ val keyMatch = ! it.hasPKC || it.user.publicKey == p.publicKey
1035+ it.user =
1036+ if (keyMatch) {
1037+ p
1038+ } else {
1039+ p.copy {
1040+ Timber .w(" Public key mismatch from $longName ($shortName )" )
1041+ publicKey = NodeEntity .ERROR_BYTE_STRING
1042+ }
10171043 }
1044+ it.longName = p.longName
1045+ it.shortName = p.shortName
1046+ it.channel = channel
1047+ it.manuallyVerified = manuallyVerified
1048+ if (newNode) {
1049+ serviceNotifications.showNewNodeSeenNotification(it)
10181050 }
1019- it.longName = p.longName
1020- it.shortName = p.shortName
1021- it.channel = channel
1022- it.manuallyVerified = manuallyVerified
1023- if (newNode) {
1024- serviceNotifications.showNewNodeSeenNotification(it)
10251051 }
10261052 }
10271053 }
@@ -1723,14 +1749,9 @@ class MeshService : Service() {
17231749 updateNodeInfo(info.num) {
17241750 if (info.hasUser()) {
17251751 // Check if this is a default/unknown user from firmware (node was evicted and re-created)
1726- val isDefaultName = info.user.longName.matches(Regex (" ^Meshtastic [0-9a-fA-F]{4}$" ))
1727- val isDefaultHwModel = info.user.hwModel == MeshProtos .HardwareModel .UNSET
1728- val hasExistingUser = it.user.id.isNotEmpty() && it.user.hwModel != MeshProtos .HardwareModel .UNSET
1729-
1730- // If firmware sends a default user (evicted node), preserve our existing user data
1731- val shouldPreserveExisting = hasExistingUser && isDefaultName && isDefaultHwModel
1752+ val shouldPreserve = shouldPreserveExistingUser(it.user, info.user)
17321753
1733- if (shouldPreserveExisting ) {
1754+ if (shouldPreserve ) {
17341755 // Firmware sent us a placeholder - keep all our existing user data
17351756 Timber .d(
17361757 " Preserving existing user data for node ${info.num} : " +
0 commit comments