Skip to content

uid_privacy is ignored in the URL-based / repeat-programming flow (SetupBoltcard) #52

Description

@Amperstrand

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

  1. Open the URL-based programming flow (ProgramBoltcardScreen / SetupBoltcard).
  2. Use a backend endpoint that returns valid card credentials plus "uid_privacy": "Y".
  3. Program a blank/default NTAG424 card.
  4. 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:

  1. Parse uid_privacy from the backend response.

  2. Derive a boolean, for example:

    const privateUID = json.uid_privacy == 'Y';
  3. After await Ntag424.AuthEv2First('00', key0) and before finalizing provisioning, call:

    if (privateUID) {
      await Ntag424.setPrivateUid();
    }
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions