Skip to content

feat(nr-app): accept @username and trustroots.org addresses at setup#256

Open
leon-wbr wants to merge 4 commits into
fix/235-nip05-case-insensitivefrom
feat/208-flexible-trustroots-identifier
Open

feat(nr-app): accept @username and trustroots.org addresses at setup#256
leon-wbr wants to merge 4 commits into
fix/235-nip05-case-insensitivefrom
feat/208-flexible-trustroots-identifier

Conversation

@leon-wbr

@leon-wbr leon-wbr commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Refs #208 (replaces #251, whose description carried an incorrect rationale for rejecting email)

⚠️ Stacked on #250 (fix/235-nip05-case-insensitive). Base is that branch, not main — merge #250 first and this will retarget cleanly.

The lint refactor that was briefly on this branch now lives in #257, which is independent and based on main.

What this does

The setup field asked for a "Trustroots Account" without saying what that meant, and accepted only a bare username. It now takes the three shapes that can be resolved to a username without a lookup:

Input Result
alice alice
@Alice alice
Alice@Trustroots.org alice

The code-entry fallback in onboarding/trustroots.tsx now goes through the same validator (it was doing a raw .trim().toLowerCase(), so @alice would have been sent un-stripped). The accepted formats are handled silently rather than advertised under the field — the label still asks for a username, which is what we want people to type.

Why an arbitrary email is still rejected

Not because we cannot resolve one — the earlier PR said that, and it was wrong. nr-bridge reads the Trustroots users collection directly, where email sits next to username as a unique, lowercased field, so an email→username lookup is entirely buildable.

It is a deliberate choice. Usernames are already public; emails are not. An email-keyed lookup would turn request_token into an oracle for whether a given address has a Trustroots account at all — free user enumeration against a set of addresses an attacker already holds. So the input is rejected with a short, friendly error pointing at the username, and the code comment now states the real reason.

#208 stays open: making email work is a product/privacy decision (and likely a rate-limited, authenticated endpoint), not a missing capability.

Tests

pnpm test in nr-app: 99 passing. Covers all three accepted shapes plus the rejected ones (foreign-domain email, multiple @, bare @).

leon-wbr added 3 commits July 13, 2026 01:52
Users reach for whatever identifier they have to hand, so the setup
field now takes the three shapes that resolve to a username without a
lookup: alice, @alice and alice@trustroots.org.

A non-Trustroots email is still rejected, with copy pointing at the
username: mapping an arbitrary email to a username would need an
email->username endpoint Trustroots does not expose, and exposing one
invites user enumeration. See OVERVIEW.md.

Refs #208
The rejection copy and comment claimed an arbitrary email could not be
mapped to a username because Trustroots exposes no email->username
endpoint. That is wrong: nr-bridge reads the Trustroots users collection
directly, where email is a unique, lowercased field next to username.

Rejecting email is a choice, not a limit. Usernames are already public,
emails are not, so an email-keyed lookup would make request_token an
oracle for whether someone has a Trustroots account at all. Say that in
the comment, and give the user a short, friendly error instead.

Refs #208
Cover lowercase, uppercase and mixed-case input explicitly instead of
asserting twice against a name that could belong to a real Trustroots
user.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant