meshcore/fix: short name should be 1st 4 hex digits of public key (#679)

This commit is contained in:
Ben Allfree
2026-04-04 00:40:49 -07:00
committed by GitHub
parent 7a21de7cda
commit 7806efb2cf
2 changed files with 41 additions and 5 deletions
+24 -3
View File
@@ -34,7 +34,9 @@ Connection type is detected automatically from the target string:
Node identities are derived from the first four bytes (eight hex characters)
of each contact's 32-byte public key, formatted as ``!xxxxxxxx`` to match
the canonical node-ID schema used across the system.
the canonical node-ID schema used across the system. Ingested
``user.shortName`` is the first four hex digits of that key (two bytes),
not the advertised name.
"""
from __future__ import annotations
@@ -118,6 +120,25 @@ def _meshcore_node_id(public_key_hex: str | None) -> str | None:
return "!" + public_key_hex[:8].lower()
def _meshcore_short_name(public_key_hex: str | None) -> str:
"""Return the first four hex digits of a MeshCore public key as short name.
Meshtastic-style ``shortName`` fields are four characters wide; MeshCore
ingest uses the leading two bytes of the 32-byte public key in lowercase
hex so the label is stable and unique per key prefix.
Parameters:
public_key_hex: Full public key as a hex string from the MeshCore API.
Returns:
Four lowercase hex characters, or an empty string when the key is
missing or shorter than four hex digits.
"""
if not public_key_hex or len(public_key_hex) < 4:
return ""
return public_key_hex[:4].lower()
def _pubkey_prefix_to_node_id(contacts: dict, pubkey_prefix: str) -> str | None:
"""Look up a canonical node ID by six-byte public-key prefix.
@@ -153,7 +174,7 @@ def _contact_to_node_dict(contact: dict) -> dict:
"lastHeard": contact.get("last_advert"),
"user": {
"longName": name,
"shortName": name[:4] if name else "",
"shortName": _meshcore_short_name(pub_key),
"publicKey": pub_key,
},
}
@@ -180,7 +201,7 @@ def _self_info_to_node_dict(self_info: dict) -> dict:
"lastHeard": int(time.time()),
"user": {
"longName": name,
"shortName": name[:4] if name else "",
"shortName": _meshcore_short_name(pub_key),
"publicKey": pub_key,
},
}
+17 -2
View File
@@ -39,6 +39,7 @@ from data.mesh_ingestor.providers.meshcore import ( # noqa: E402 - path setup
_make_connection,
_make_event_handlers,
_meshcore_node_id,
_meshcore_short_name,
_process_contact_update,
_process_contacts,
_process_self_info,
@@ -434,6 +435,7 @@ def test_meshcore_node_snapshot_items_with_contacts(monkeypatch):
node_id, node_dict = items[0]
assert node_id == "!aabbccdd"
assert node_dict["user"]["longName"] == "Alice"
assert node_dict["user"]["shortName"] == "aabb"
iface.close()
@@ -537,6 +539,18 @@ def test_meshcore_node_id_none_on_empty():
assert _meshcore_node_id(None) is None # type: ignore[arg-type]
def test_meshcore_short_name_first_four_hex_digits():
"""_meshcore_short_name returns the first four hex chars, lowercased."""
assert _meshcore_short_name("AABBccdd" + "00" * 28) == "aabb"
def test_meshcore_short_name_empty_when_too_short():
"""_meshcore_short_name returns '' when the key has fewer than four hex digits."""
assert _meshcore_short_name("") == ""
assert _meshcore_short_name("abc") == ""
assert _meshcore_short_name(None) == "" # type: ignore[arg-type]
# ---------------------------------------------------------------------------
# _pubkey_prefix_to_node_id
# ---------------------------------------------------------------------------
@@ -576,7 +590,7 @@ def test_contact_to_node_dict_basic_fields():
node = _contact_to_node_dict(contact)
assert node["lastHeard"] == 1700000000
assert node["user"]["longName"] == "Alice"
assert node["user"]["shortName"] == "Alic"
assert node["user"]["shortName"] == "aabb"
assert node["user"]["publicKey"] == contact["public_key"]
@@ -616,7 +630,7 @@ def test_self_info_to_node_dict_basic_fields():
self_info = {"name": "MyNode", "public_key": "bb" * 32}
node = _self_info_to_node_dict(self_info)
assert node["user"]["longName"] == "MyNode"
assert node["user"]["shortName"] == "MyNo"
assert node["user"]["shortName"] == "bbbb"
assert node["user"]["publicKey"] == "bb" * 32
assert isinstance(node["lastHeard"], int)
@@ -649,6 +663,7 @@ def test_interface_update_and_snapshot_contacts():
node_id, node_dict = snapshot[0]
assert node_id == "!aabbccdd"
assert node_dict["user"]["longName"] == "Bob"
assert node_dict["user"]["shortName"] == "aabb"
def test_interface_lookup_node_id_by_prefix():