Sync dev docs with today's work: README, CHANGELOG, TODO, llms.txt cleanup

README now presents the widget as the complete login surface (four
methods, method-aware events, window.bitlogin session API) and retires
the stale 'NIP-46/NIP-07 interop deferred' line. CHANGELOG gains a
2026-08-04 entry -- leading with the 'wasm-unsafe-eval' CSP requirement
and the service-worker cache:'reload' pattern, since a vendored site
without them has broken password flows. TODO records the shipped
expansion and the owner follow-ups: live-fire Amber QR and real-device
passkey tests, the new passkey derivation compatibility contract, and
the unchanged NIP-46 persistence gate. Removes a dangling on-ramp
fragment my earlier llms.txt edit left fused to the passkey bullet.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Fable 5 committed 2026-08-04 12:58:32 -04:00
1 parent 8079d90cf8
commit 36cd3eb853
4 files changed
+77 -12

No files matched your search

+30
View File
@@ -6,6 +6,36 @@ site with its own vendored copy (see "Updating your integration" in
sitting on an older vendored copy is missing a fix or behavior change it
would plausibly want. Newest first.
## 2026-08-04
- **CSP fix every self-hosting site needs: add `'wasm-unsafe-eval'` to
`script-src`.** Argon2id (hash-wasm) compiles a WASM module in the crypto
worker; a `script-src 'self'` policy without that keyword blocks
`WebAssembly.compile` and breaks every password flow. The keyword permits
WASM compilation only — JS `eval` stays banned. Related: if your service
worker precaches the widget, fetch with `cache: "reload"` during install —
an asset revalidating to a 304 keeps its OLD stored headers, and a worker
script cached with a stale CSP runs under that stale policy (this shipped
once; see the demo's `sw.js` for the pattern).
- **One login surface, four methods.** Behind a collapsed "More sign-in
options" menu (password stays primary): NIP-07 extension delegation,
NIP-46 remote signers (bunker:// paste + a dot-style nostrconnect QR;
NIP-44 transport only; memory-only sessions), and passkey sign-in
(WebAuthn PRF derives the account credential under a frozen contract —
zero site setup). Alternative-method sessions are signer-only: no vault
(`requestNwcConnection` resolves null), no persistence.
- **Host API additions.** `bitlogin-login` now carries `detail.method` and
`detail.capabilities` (existing `detail.publicKey` unchanged);
`window.bitlogin` gains `activeMethod()` / `activeSession()` — use these
for session state, NOT `isActiveSigner()`, which stays a window.nostr
ownership check and is deliberately false during NIP-07 sessions.
`window.nostr` is now an element-routed provider that follows the active
signer.
- **UI polish.** Screen headers with icon back buttons, right-aligned
"Forgot password?", icon+description option rows with 56px touch targets.
- New widget dependency bundled in: `qrcode-generator` (QR for
nostrconnect). File count and deployment layout unchanged.
## 2026-07-30
- **Widget: `requestNwcConnection()` — the Connection Vault authorization
+19 -3
View File
@@ -57,9 +57,23 @@ must be deployed side by side — the main script resolves the worker's URL at
runtime relative to its own location, so this works from any path, not just
the site root.
The widget is a complete login surface, not just the password flow: behind
"More sign-in options" it also offers a NIP-07 signer extension (when one is
detected), a NIP-46 remote signer (bunker:// paste or a scannable
nostrconnect QR for phone signers like Amber), a passkey (WebAuthn PRF —
zero site setup, the passkey deterministically derives the account
credential), §SF10 key import, and phrase recovery. The `bitlogin-login`
event reports `detail.method` (`'bitlogin' | 'nip07' | 'nip46'`) and
`detail.capabilities`, and `window.bitlogin.activeMethod()` /
`activeSession()` answer session state for every method. See
`docs/login-methods.md` and `docs/passkey-login.md`.
Once a user signs in, `window.nostr` is installed with the de facto NIP-07
shape (`getPublicKey`, `signEvent`, `getRelays`, `nip44.encrypt/decrypt`), so
existing Nostr web apps work against it unmodified. Private keys are held in
existing Nostr web apps work against it unmodified — routed to whichever
signer backs the session (the worker for password/passkey accounts, the
worker-held NIP-46 client for remote-signer sessions; NIP-07 sessions leave
the slot to the extension that owns it). Private keys are held in
the worker and are not handed to the main thread by the signing APIs — those
return public keys, signed events, and ciphertext only.
@@ -358,8 +372,10 @@ HKDF, ScalarExpand, AES-256-GCM, JCS, fixed padding buckets).
- Phase 2 messaging (NIP-17 inbox/compose) — the NIP-44 primitive is built
and tested, but no conversation UI is wired up.
- Phase 3 application redirect-auth flow (§26.3) and NIP-46/NIP-07 browser
extension interop beyond the `window.nostr` shim.
- Phase 3 application redirect-auth flow (§26.3). (NIP-07 and NIP-46
sign-in, anticipated by §26.4, shipped 2026-08-04 — see
`docs/login-methods.md`; NIP-46 credential *persistence* stays gated on
the external vault review.)
- NIP-49 `ncryptsec` export (§28.2) — deliberately left out rather than
shipped unverified against official test vectors; plain `nsec`/`npub`
(NIP-19) export is implemented instead.
+27 -1
View File
@@ -1,6 +1,32 @@
# BitLogin — open items
Updated: 2026-07-31
Updated: 2026-08-04
## Login-surface expansion (2026-08-04) — shipped, with owner follow-ups
One login surface, four methods (`login-methods.md`, `passkey-login.md`):
password (primary), NIP-07 extension, NIP-46 remote signer (memory-only),
and passkey via WebAuthn PRF. OAuth on-ramps were built, then removed the
same day for requiring per-site provider registration
(`centralized-onramps.md`, superseded, kept on the record). Also shipped:
the deployment-CSP `'wasm-unsafe-eval'` fix (live password flows were
broken since 2026-07-31), the service-worker `cache: "reload"` precache
fix, `window.bitlogin.activeMethod()/activeSession()`, and welcome/sign-in
UI polish.
Owner action items:
1. **Live-fire the NIP-46 QR with Amber** on bitlogin.network (flow was
verified against a fake bunker in tests, not yet against a real phone
signer end-to-end).
2. **Live-fire passkey sign-in on a real device** (Chrome + Google Password
Manager, and once on iOS Safari). PRF cannot be exercised in CI; the
ceremony paths are untested against real authenticators.
3. **Passkey derivation is a new compatibility contract** —
`packages/widget/src/passkey.test.ts` known-answer vectors carry the
same never-update-the-expected-value rule as `knownAnswer.test.ts`.
4. NIP-46 credential *persistence* (vault record) stays gated on the
external security review, as before.
## Entropy audit (2026-07-31)
+1 -8
View File
@@ -40,14 +40,7 @@ deployment above.
per-credential); passkeys are per-site (rpId) -- cross-site portability
is the capsule account's job. Rotating the password is the graduation
step to fully self-held. Requires a PRF-capable browser/authenticator;
the widget shows an honest fallback message otherwise. The service acts as the password manager for a REAL
capsule account (it holds the unlock secret, never the key); rows render
under "Use an account you already have" with the custody statement
("<Service> manages your sign-in") as the sub-label, new users can create
a fresh identity or import an existing nsec, and the dashboard nudges
toward claiming the recovery phrase ("Secure your account"). Hosts must
add the service origin to CSP connect-src. Contract and threat model:
docs/centralized-onramps.md.
the widget shows an honest fallback message otherwise.
- One login surface, several methods: if the visitor's browser has a NIP-07
signer extension, the welcome screen offers "Use your Nostr extension
instead" below the primary username/password path, and every visitor gets