[BUG] Contact QR code leaves out the node's public key, so Meshtastic apps refuse it #72

Closed
opened 2026-10-27 16:49:59 +01:00 by adam · 1 comment
Owner

Summary

The contact link behind Copy Import URL and Show QR Code on the node page never includes the node's public key. /api/node/{node_id}/qr builds a SharedContact with the node id, names, hardware model and role. It never sets user.public_key (meshview/web_api/api.py, api_node_qr).

Why it matters

  • Current Meshtastic apps refuse to import a contact that has no public key:

    • Android 2.8.2 and later shows "This contact has no public key, so it cannot be imported" and removes the Import button (Meshtastic-Android#7050).
    • iOS 2.7.22 and later shows "This contact does not include a public key, so it cannot be added."

    On those apps the Meshview QR code does nothing.

  • Older apps send the contact to the radio as add_contact. On 2.7.x firmware, NodeDB::addFromContact copies the empty key over the key the radio already holds for that node. Direct messages to that node then fail with PKI_SEND_FAIL_PUBLIC_KEY until it broadcasts NodeInfo again. Firmware no longer falls back to the channel key for direct messages. The overwrite is fixed in firmware develop by firmware#11432.

  • meshtastic/design#145 sets the cross-client rule: never send add_contact with an empty public key, whether it comes from a QR code, a link or an NFC tag.

The apps' own Share Contact QR codes include the key.

Steps to reproduce

  1. Open the page of a node that has sent NODEINFO with a public key. Any node on firmware 2.5 or later that is not in licensed mode will do.
  2. Click Copy Import URL, or call /api/node/<node_id>/qr and take meshtastic_url.
  3. Base64url-decode the part after # and parse it as meshtastic.protobuf.SharedContact.
  4. Optionally, scan the QR code with a current Android or iOS Meshtastic app.

Expected: user.public_key holds the node's 32-byte public key, and the app imports the contact.

Actual: user.public_key is empty. Current apps refuse the import. Older apps on 2.7.x firmware erase the key the radio already knew.

Notes

  • Meshview dropped its node_public_key table in 3.0.7. The key is still available, though: packet.payload keeps each NODEINFO_APP packet, and its User.public_key is the node's key.
  • Seen on develop at aabb099 (3.0.9). It does not depend on the database backend; reproduced with SQLite.
## Summary The contact link behind **Copy Import URL** and **Show QR Code** on the node page never includes the node's public key. `/api/node/{node_id}/qr` builds a `SharedContact` with the node id, names, hardware model and role. It never sets `user.public_key` (`meshview/web_api/api.py`, `api_node_qr`). ## Why it matters - Current Meshtastic apps refuse to import a contact that has no public key: - Android 2.8.2 and later shows "This contact has no public key, so it cannot be imported" and removes the Import button ([Meshtastic-Android#7050](https://github.com/meshtastic/Meshtastic-Android/pull/7050)). - iOS 2.7.22 and later shows "This contact does not include a public key, so it cannot be added." On those apps the Meshview QR code does nothing. - Older apps send the contact to the radio as `add_contact`. On 2.7.x firmware, `NodeDB::addFromContact` copies the empty key over the key the radio already holds for that node. Direct messages to that node then fail with `PKI_SEND_FAIL_PUBLIC_KEY` until it broadcasts NodeInfo again. Firmware no longer falls back to the channel key for direct messages. The overwrite is fixed in firmware `develop` by [firmware#11432](https://github.com/meshtastic/firmware/pull/11432). - [meshtastic/design#145](https://github.com/meshtastic/design/issues/145) sets the cross-client rule: never send `add_contact` with an empty public key, whether it comes from a QR code, a link or an NFC tag. The apps' own **Share Contact** QR codes include the key. ## Steps to reproduce 1. Open the page of a node that has sent NODEINFO with a public key. Any node on firmware 2.5 or later that is not in licensed mode will do. 2. Click **Copy Import URL**, or call `/api/node/<node_id>/qr` and take `meshtastic_url`. 3. Base64url-decode the part after `#` and parse it as `meshtastic.protobuf.SharedContact`. 4. Optionally, scan the QR code with a current Android or iOS Meshtastic app. **Expected:** `user.public_key` holds the node's 32-byte public key, and the app imports the contact. **Actual:** `user.public_key` is empty. Current apps refuse the import. Older apps on 2.7.x firmware erase the key the radio already knew. ## Notes - Meshview dropped its `node_public_key` table in 3.0.7. The key is still available, though: `packet.payload` keeps each NODEINFO_APP packet, and its `User.public_key` is the node's key. - Seen on `develop` at aabb099 (3.0.9). It does not depend on the database backend; reproduced with SQLite. <!-- github-sync-id:6046537937 -->
adam closed this issue 2026-10-28 01:36:30 +01:00
Author
Owner

this PR was added and will be in next version

this PR was added and will be in next version <!-- github-comment-id:6457231862 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/meshview#72