Title: uid_privacy is ignored in the URL-based / repeat-programming flow (SetupBoltcard), so random UID only works in the single-card JSON flow
Summary
There are two different card-programming flows in the Android app, and they do not behave the same way with respect to uid_privacy / random UID:
- The single-card JSON flow honors
uid_privacy.
- The URL-based / repeat-programming flow ignores
uid_privacy.
This means random/private UID works when programming a single card from imported auth JSON, but it does not work when programming many cards through the “program from URL” / “Write again” path.
Affected code paths
Flow that works
Single-card / imported JSON flow:
src/components/DisplayAuthInfo.js
src/screens/CreateBoltcardScreen.js
This flow parses json.uid_privacy == 'Y' into a privateUID boolean, and CreateBoltcardScreen.writeAgain() calls await Ntag424.setPrivateUid() when that flag is true.
Flow that is buggy
URL-based / repeat-programming flow:
src/screens/ProgramBoltcardScreen.js
src/components/SetupBoltcard.js
ProgramBoltcardScreen renders SetupBoltcard, and SetupBoltcard is the flow used for repeated programming (Write again).
Exact bug
SetupBoltcard.js fetches per-card JSON from the backend, but it only reads:
K0 / k0
K1 / k1
K2 / k2
K3 / k3
K4 / k4
LNURLW / lnurlw_base
It does not read uid_privacy.
It also never stores any privateUID flag and never calls Ntag424.setPrivateUid().
So even if the backend returns something like:
{
"k0": "...",
"k1": "...",
"k2": "...",
"k3": "...",
"k4": "...",
"lnurlw_base": "lnurlw://...",
"uid_privacy": "Y"
}
the uid_privacy field is ignored in SetupBoltcard, and the card is programmed without enabling private/random UID.
Why this is a real logic bug
The app already contains the implementation for enabling random UID:
src/class/Ntag424.js exposes Ntag424.setPrivateUid().
The single-card flow already uses it correctly.
The repeat-programming flow simply never calls it.
So this is not a backend issue and not a card issue. It is a missing code path in SetupBoltcard.js.
How to trigger
- Open the URL-based programming flow (
ProgramBoltcardScreen / SetupBoltcard).
- Use a backend endpoint that returns valid card credentials plus
"uid_privacy": "Y".
- Program a blank/default NTAG424 card.
- Press Write again and program additional cards through the same flow.
Actual result
Cards are programmed successfully, but private/random UID is not enabled, even though the backend response requested it via uid_privacy.
Expected result
If the backend response includes "uid_privacy": "Y", the URL-based / repeat-programming flow should enable private/random UID exactly like the single-card JSON flow does.
Root cause
SetupBoltcard.js does not mirror the uid_privacy handling implemented in the single-card flow.
In other words:
CreateBoltcardScreen path: parses uid_privacy and calls setPrivateUid()
SetupBoltcard path: does not parse uid_privacy, never calls setPrivateUid()
Suggested fix
In src/components/SetupBoltcard.js:
-
Parse uid_privacy from the backend response.
-
Derive a boolean, for example:
const privateUID = json.uid_privacy == 'Y';
-
After await Ntag424.AuthEv2First('00', key0) and before finalizing provisioning, call:
if (privateUID) {
await Ntag424.setPrivateUid();
}
-
If later validation logic depends on the real UID, consider refreshing it with:
uid = await Ntag424.getCardUid();
Acceptance criteria
- Programming through
SetupBoltcard with "uid_privacy": "Y" enables private/random UID.
- Behavior matches the existing single-card JSON flow.
- Programming through
SetupBoltcard with no uid_privacy field or with "uid_privacy": "N" remains unchanged.
Title:
uid_privacyis ignored in the URL-based / repeat-programming flow (SetupBoltcard), so random UID only works in the single-card JSON flowSummary
There are two different card-programming flows in the Android app, and they do not behave the same way with respect to
uid_privacy/ random UID:uid_privacy.uid_privacy.This means random/private UID works when programming a single card from imported auth JSON, but it does not work when programming many cards through the “program from URL” / “Write again” path.
Affected code paths
Flow that works
Single-card / imported JSON flow:
src/components/DisplayAuthInfo.jssrc/screens/CreateBoltcardScreen.jsThis flow parses
json.uid_privacy == 'Y'into aprivateUIDboolean, andCreateBoltcardScreen.writeAgain()callsawait Ntag424.setPrivateUid()when that flag is true.Flow that is buggy
URL-based / repeat-programming flow:
src/screens/ProgramBoltcardScreen.jssrc/components/SetupBoltcard.jsProgramBoltcardScreenrendersSetupBoltcard, andSetupBoltcardis the flow used for repeated programming (Write again).Exact bug
SetupBoltcard.jsfetches per-card JSON from the backend, but it only reads:K0/k0K1/k1K2/k2K3/k3K4/k4LNURLW/lnurlw_baseIt does not read
uid_privacy.It also never stores any
privateUIDflag and never callsNtag424.setPrivateUid().So even if the backend returns something like:
{ "k0": "...", "k1": "...", "k2": "...", "k3": "...", "k4": "...", "lnurlw_base": "lnurlw://...", "uid_privacy": "Y" }the
uid_privacyfield is ignored inSetupBoltcard, and the card is programmed without enabling private/random UID.Why this is a real logic bug
The app already contains the implementation for enabling random UID:
src/class/Ntag424.jsexposesNtag424.setPrivateUid().The single-card flow already uses it correctly.
The repeat-programming flow simply never calls it.
So this is not a backend issue and not a card issue. It is a missing code path in
SetupBoltcard.js.How to trigger
ProgramBoltcardScreen/SetupBoltcard)."uid_privacy": "Y".Actual result
Cards are programmed successfully, but private/random UID is not enabled, even though the backend response requested it via
uid_privacy.Expected result
If the backend response includes
"uid_privacy": "Y", the URL-based / repeat-programming flow should enable private/random UID exactly like the single-card JSON flow does.Root cause
SetupBoltcard.jsdoes not mirror theuid_privacyhandling implemented in the single-card flow.In other words:
CreateBoltcardScreenpath: parsesuid_privacyand callssetPrivateUid()SetupBoltcardpath: does not parseuid_privacy, never callssetPrivateUid()Suggested fix
In
src/components/SetupBoltcard.js:Parse
uid_privacyfrom the backend response.Derive a boolean, for example:
After
await Ntag424.AuthEv2First('00', key0)and before finalizing provisioning, call:If later validation logic depends on the real UID, consider refreshing it with:
Acceptance criteria
SetupBoltcardwith"uid_privacy": "Y"enables private/random UID.SetupBoltcardwith nouid_privacyfield or with"uid_privacy": "N"remains unchanged.