Skip to content

feat(nip46): show user's kind-0 profile (name, about, NIP-05) after Amber login - #79

Merged
oth-body merged 2 commits into
masterfrom
feat/nip46-profile-on-login
Sep 15, 2026
Merged

oth-body merged 2 commits into
masterfrom
feat/nip46-profile-on-login

Conversation

@oth-body

Copy link
Copy Markdown
Owner

Bug Description

The user's bug report (second part): "it doesn't give a success message on the actual device, it needs to give a success message there and also show the profile of the person when it's working in HOOT."

After a successful NIP-46 QR pairing, the home screen showed only the raw 16-char pubkey prefix (m.publicKey[:16]). There was no code anywhere in the codebase that fetched the user's kind-0 (NIP-01 profile metadata) event, and no UI element to render the name / about / picture / NIP-05 from one.

Fix

Wires the kind-0 profile fetch end-to-end from session → TUI → home screen:

  1. nip46.Session.FetchProfile(ctx, userPubKey) — new method that queries the same relay connections opened by ConnectRelays for a kind-0 event authored by the user. No extra dial cost (amortises the QR-pairing latency). 6-second timeout so a dead relay doesn't block the TUI login flow. Returns (nil, nil) — not an error — when the user has no kind-0 event, so the caller falls back to the npub display without raising an error toast.

  2. hoot.go:OnCheckQR — after GetPublicKey returns, calls FetchProfile and returns the result alongside the pubkey. Successful fetch is cached in the existing cache.profiles table with 24h TTL.

  3. tui.qrSuccessMsg — now carries the profile alongside the pubkey. The success message becomes "Logged in as " when a name is available; falls back to "Logged in via Amber!" otherwise.

  4. tui.viewHome — when currentProfileAbout or currentProfileNIP05 is set, renders them under the title in dim style. The NIP-05 gets a ✓ prefix to communicate verification status at a glance.

How to Verify

  1. go run . and pick "Scan QR with Amber".
  2. After Amber approves, the home screen shows "🦉 Hoot - " with the about line + NIP-05 below (if you've set them in Amber).
  3. Run with a profile-store user (nsec login) — the existing currentProfileName is used unchanged, no regression.
  4. Run with a user who has no kind-0 event — the home screen falls back to the 16-char pubkey prefix.

Test Plan

  • TestProfileMetadataJSONRoundTrip — pins the wire format
  • TestProfileMetadataOmitsEmptyFields — pins the omit-empty contract
  • TestFetchProfileRejectsEmptyPubKey — input-validation guard
  • TestFetchProfileRejectsNoRelays — "called too early" guard
  • TestProfileNameIsRenderable — covers ASCII/emoji/unicode/whitespace/markup cases
  • Existing tui tests updated to the new OnCheckQR signature
  • Full suite green (go test ./...)
  • go vet ./... clean
  • Manual verification of the four scenarios above

Risk Assessment

Low. The change is purely additive on the success path:

  • New fields on the TUI Model (currentProfileAbout, currentProfileNIP05) are only set by the new code path, and only displayed when non-empty.
  • The success message change ("Logged in as X" vs "Logged in via Amber!") is purely cosmetic — the underlying loggedIn/publicKey state is unchanged.
  • FetchProfile failures are non-fatal by design — they degrade gracefully to npub display, identical to the pre-change behaviour.
  • The cache write is best-effort (_ =); a cache failure doesn't break sign-in.

The TUI's OnCheckQR signature changed (func() (string, error) → func() (string, *nip46.ProfileMetadata, error)). All four test files using SetCallbacks were updated; no other callers exist outside hoot.go.

…ive relays

The user's bug report: 'it doesn't give a success message on the actual
device, it needs to give a success message there and also show the
profile of the person when it's working in HOOT.'

Right now the TUI shows nothing more than the 16-char pubkey prefix
after QR login — no name, no about, no picture, no NIP-05. There's
no code anywhere that fetches the user's kind-0 (NIP-01 profile)
metadata after a successful NIP-46 pairing.

This commit adds Session.FetchProfile(ctx, userPubKey), which queries
the same relay connections opened by ConnectRelays for a kind-0
event by UserPublicKey. No extra dial cost (amortises the QR-pairing
latency), 6s timeout so the TUI never blocks on a dead relay, and
returns (nil, nil) — not an error — when no kind-0 event exists so
the caller can fall back to npub display without raising an error
toast.

The TUI integration, cache persistence, and home-screen rendering
land in the next step of this branch.

Tests: profile.go is testable as a unit without a real relay; the
TUI integration test will follow.
…mber login

The user's bug report: 'it doesn't give a success message on the
actual device, it needs to give a success message there and also
show the profile of the person when it's working in HOOT.'

After QR pairing succeeds, the home screen showed only the raw
16-char pubkey prefix. There's no code anywhere in the repo that
fetches the user's kind-0 (NIP-01 profile metadata) event. This
commit wires that in end-to-end.

- nip46.Session.FetchProfile(ctx, userPubKey) queries the same
  relay connections opened by ConnectRelays (no extra dial cost,
  amortises the QR-pairing latency) for kind=0 events authored
  by the user. 6s timeout so a dead relay doesn't block the TUI
  login flow. Returns (nil, nil) — not an error — when the user
  has no kind-0 event, so callers fall back to the npub display
  without raising an error toast.
- The OnCheckQR callback in hoot.go now also calls FetchProfile
  and returns the result alongside the pubkey. Successful fetch
  is cached in the existing profiles table with 24h TTL (matches
  the kind-0 re-publish cadence of most signers).
- The TUI's qrSuccessMsg now carries the profile. The success
  message says 'Logged in as <name>' when we have one, else
  'Logged in via Amber!' (unchanged fallback). viewHome renders
  the about line and NIP-05 (✓ alice@example.com) under the
  name when present.
- Test files updated to the new OnCheckQR signature. New
  profile_test.go covers the JSON round-trip, the omit-empty-
  fields contract, and the FetchProfile input-validation guards.
- ProfileMetadata is JSON-shaped to match what kind-0 events
  contain on the wire (name, about, picture, nip05 — all
  optional), so unmarshal survives signer quirks.

Tests: +5 new in nip46/profile_test.go, existing nip46+tui tests
updated, full suite green, go vet clean.
@oth-body
oth-body merged commit de32c6a into master Sep 15, 2026
7 checks passed
@oth-body
oth-body deleted the feat/nip46-profile-on-login branch September 15, 2026 21:01
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