feat(sign-in): an npub, recognised, confirmed as read-only, then written

Phase 4 of docs/npub-sign-in.md. The field accepts a third thing.

CredentialParser recognises npub1... and nostr:npub1... as
SignInCredential.NostrPublicKey: thirty-two bytes under the npub prefix
that name a point on the curve -- the counterpart of the isValid() a
secret is checked with, since not every x coordinate has a point above it.
PublicKeyOnly goes, and its string with it; an npub that does not decode,
or names no point, is InvalidKey. Hex stays a secret: a private key and an
x-only public key are the same size, the confirm step shows the derived
npub so a public key pasted as hex is visible for what it is, and guessing
would never fire when it mattered, since an x coordinate is almost always
also a valid scalar. The test pins the vector's own public key, pasted as
hex, landing on a different npub.

The confirm step's third arm says what the user is about to get and not
get, once, before the choice: this profile and the people it follows;
messages closed and nothing sent; paste the nsec later to open it. The
landing caption, the field's label and its placeholder name the third
input, the last with "to look around" for a user who does not know the
word read-only. The view model takes the third writer the way it takes the
other two and commits through one shared write-and-map.

signInToProfile is idempotent by pubkey. Until now nothing called it twice
for one key -- the writers refused a second sign-in before it got there.
Pasting the nsec of a key held read-only is the first path that signs in a
pubkey whose account already exists, and a second placeholder would be two
kind-0 rows for one pubkey, two accounts disagreeing about which is this
one. A repository test signs in twice and counts one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pulled-From: curated/curated@bfad1f39a2
This commit is contained in:
Kgothatso Ngako
2026-09-12 20:32:54 +02:00
parent 6532bfc45f
commit 4c04d3b12b
10 changed files with 214 additions and 49 deletions

View File

@@ -264,7 +264,6 @@
<string name="this_will_be_shown_when_people_open_your">This will be shown when people open your profile.</string>
<string name="this_will_be_the_display_name_for_this_chat">This will be the display name for this chat room.</string>
<string name="this_will_be_the_display_name_for_your">This will be the display name for your profile and also important for search.</string>
<string name="this_will_give_you_read_only_access_to_the">This will give you read only access to the profile.</string>
<string name="read_only">Read only</string>
<string name="this_will_give_you_write_access_to_the">This will give you write access to the profile.</string>
<string name="torch_will_be_broadcast_what_you_publish_to">Mantra broadcasts what you publish to a distributed set of relays, so it stays decentralised.</string>
@@ -649,13 +648,13 @@
<string name="copied_the_raw_json">Copied the raw JSON</string>
<!-- Sign in: docs/nsec-sign-in.md, phase 4. -->
<string name="a_password_protected_key_ncryptsec_is_not">A password-protected key (ncryptsec) is not supported yet. Decrypt it in the app it came from and paste the nsec.</string>
<string name="an_npub_is_a_public_key_mantra_needs_the">An npub is a public key. Mantra needs the secret key, the nsec, to sign as you.</string>
<string name="enter_a_recovery_phrase_or_an_nsec_to_sign_in">Enter a recovery phrase or an nsec to sign in.</string>
<string name="paste">Paste</string>
<string name="recognised_as_a_nostr_secret_key_no_wallet">Recognised as a nostr secret key. No wallet comes with it.</string>
<string name="recognised_as_a_recovery_phrase_it_also">Recognised as a recovery phrase. It also restores the wallet.</string>
<string name="recovery_phrase_or_nsec">Recovery phrase or nsec</string>
<string name="sign_in_with_a_recovery_phrase_or_an_nsec">Sign in with a recovery phrase or an nsec</string>
<string name="recognised_as_a_public_key_you_will_see">Recognised as a public key. You will see this profile and the people it follows; messages stay closed and nothing can be sent. Paste the nsec later to open it.</string>
<string name="recovery_phrase_nsec_or_npub">Recovery phrase, nsec or npub</string>
<string name="sign_in_with_a_recovery_phrase_an_nsec_or">Sign in with a recovery phrase, an nsec, or an npub to look around</string>
<string name="signed_in">Signed in</string>
<string name="signing_you_in">Signing you in…</string>
<string name="that_is_not_a_recovery_phrase_or_a_nostr_key">That is not a recovery phrase or a nostr key.</string>
@@ -664,7 +663,7 @@
<string name="the_key_could_not_be_saved_on_this_device">The key could not be saved on this device.</string>
<string name="the_words_or_the_key_never_leave_this_device">Whatever you paste stays on this device. Mantra checks it, shows you the profile it opens, and writes nothing until you confirm.</string>
<string name="this_key_is_already_on_this_device">This key is already on this device.</string>
<string name="twelve_words_or_nsec1">Twelve words, or nsec1…</string>
<string name="twelve_words_nsec1_or_npub1">Twelve words, nsec1… or npub1…</string>
<string name="use_a_different_key">Use a different key</string>
<string name="you_are_signing_in_as">You are signing in as</string>
<!-- Sign in: the search that found nothing, docs/nsec-sign-in.md, phase 5. -->