Part of #353. Prerequisite for every user-facing flow in the epic.
Problem or Motivation
The seed-identity feature depends entirely on CMD_EXPORT_PRIVATE_KEY and CMD_IMPORT_PRIVATE_KEY, both of which can be compiled out of the firmware. When they are, the radio answers RESP.DISABLED and the client raises PrivateKeyError('disabled') (client.ts:1661).
Research for #353 found the flags are enabled by default — ENABLE_PRIVATE_KEY_IMPORT=1 and ENABLE_PRIVATE_KEY_EXPORT=1 live in [arduino_base] in the firmware's platformio.ini, inherited by every platform base and every board variant, and no variant overrides them. But the flag sits under the comment "NOTE: comment these out for more secure firmware", which actively invites security-conscious builders to disable it, and prebuilt vendor images are outside our visibility.
Without a probe, a user on such a build walks through a multi-step wizard — generating a phrase, writing it down, confirming the words — and only discovers at the final write that their radio will not accept it. The two capabilities are also independent: a build can permit import but not export, or the reverse.
Proposed Solution
Detect both capabilities once per session and expose them on the store, so the UI can hide or disable the feature up front rather than failing at the end.
- Probe during the connect flow in useMeshCore.ts, alongside the existing best-effort hydrate round-trips that already tolerate older firmware (
readAutoAddBits is the precedent).
- Export is safely probeable: call
exportPrivateKey and catch PrivateKeyError('disabled') / ('unsupported'). Zero the returned key immediately — this probe must not leave the identity resident, and the existing method's TSDoc already makes that the caller's responsibility.
- Import cannot be probed without performing it. Infer it: treat it as available when export is, and surface the real failure if a later import is refused. Document the inference rather than implying it was tested.
- Add the result to
MeshState as a capability field. It describes the connected radio, so it resets on disconnect and is not a preference — it must not enter RadioPreferences or the per-radio blob.
- Gate the phase 1 and 2 entry points on it, with a localized explanation naming the build flag when unavailable, so a user can act on it.
Notes
Firmware predating the commands answers ERR rather than RESP.DISABLED; MeshCoreClient.privateKeyError already maps both onto distinguishable PrivateKeyError reasons, so the probe can tell "compiled out" from "too old" and say which.
Part of #353. Prerequisite for every user-facing flow in the epic.
Problem or Motivation
The seed-identity feature depends entirely on
CMD_EXPORT_PRIVATE_KEYandCMD_IMPORT_PRIVATE_KEY, both of which can be compiled out of the firmware. When they are, the radio answersRESP.DISABLEDand the client raisesPrivateKeyError('disabled')(client.ts:1661).Research for #353 found the flags are enabled by default —
ENABLE_PRIVATE_KEY_IMPORT=1andENABLE_PRIVATE_KEY_EXPORT=1live in[arduino_base]in the firmware'splatformio.ini, inherited by every platform base and every board variant, and no variant overrides them. But the flag sits under the comment "NOTE: comment these out for more secure firmware", which actively invites security-conscious builders to disable it, and prebuilt vendor images are outside our visibility.Without a probe, a user on such a build walks through a multi-step wizard — generating a phrase, writing it down, confirming the words — and only discovers at the final write that their radio will not accept it. The two capabilities are also independent: a build can permit import but not export, or the reverse.
Proposed Solution
Detect both capabilities once per session and expose them on the store, so the UI can hide or disable the feature up front rather than failing at the end.
readAutoAddBitsis the precedent).exportPrivateKeyand catchPrivateKeyError('disabled')/('unsupported'). Zero the returned key immediately — this probe must not leave the identity resident, and the existing method's TSDoc already makes that the caller's responsibility.MeshStateas a capability field. It describes the connected radio, so it resets on disconnect and is not a preference — it must not enterRadioPreferencesor the per-radio blob.Notes
Firmware predating the commands answers
ERRrather thanRESP.DISABLED;MeshCoreClient.privateKeyErroralready maps both onto distinguishablePrivateKeyErrorreasons, so the probe can tell "compiled out" from "too old" and say which.