fix: survive orphaned extension context + add reset-to-init to main screen - #26
Merged
Merged
Conversation
…init Two robustness fixes surfaced while live-testing the passkey identity flow. Content-script resilience (injected.js, nip98-interceptor.js): When the extension is reloaded/updated while a consuming page stays open, the content script is orphaned and every chrome.runtime call throws "Extension context invalidated." High-frequency callers (e.g. Proton's event-manager poll) flooded the console with an identical stack forever. Now the bridge latches the dead context on first sight, warns once, tells the page interceptor to restore native fetch/XHR, and answers all later requests with a silent null. A tab reload re-injects fresh scripts. Reset-to-init (popup): The wipe-and-return-to-setup action (handleForgetKey) was only reachable from the unlock screen, so an unlocked user had no way back to the setup screen — the sole entry point for passkey-derived identity creation. Add a "Start over" footer link on the main screen wired to the same handler, so existing users can reset to init (and reach passkey creation) without locking first. Styled with the existing --danger token. Co-Authored-By: jjohare <github@thedreamlab.uk>
… errors
Requesting residentKey:'preferred' asks the authenticator to create a
discoverable credential, which Podkey never uses — it stores the
credentialId and always passes it via allowCredentials at unlock. On some
TPM/security-key authenticators (e.g. tpm-fido) the resident-credential
makeCredential path fails after a successful fingerprint/UV, surfacing as a
generic NotAllowedError ("timed out or not allowed"). Switch to
residentKey:'discouraged'; hmac-secret/PRF works fine on non-resident creds.
Also surface actionable errors instead of the raw NotAllowedError:
- After create(), check getClientExtensionResults().prf.enabled — the
definitive signal that the authenticator provisioned hmac-secret — and fail
early with a clear "no PRF" message rather than persisting a credential that
can never unlock.
- Translate NotAllowedError/AbortError from either ceremony into a message that
names the likely causes (cancel/timeout/focus) and the two-prompt shape.
Co-Authored-By: jjohare <github@thedreamlab.uk>
Bring the user-facing docs up to date with the FIDO2 passkey feature and the PR #26 fixes. - CHANGELOG: populate [Unreleased] with the passkey master identity (derived + wrapped, PRF requirement, nsec backup), "Start over" reset, the invalidated- context resilience fix, and the passkey ceremony compatibility/error fixes. - USAGE: add a "Create a passkey-derived identity (advanced)" walkthrough (two prompts, PRF-capable authenticator, nsec backup), "Passkey unlock" for an existing key, "Start over (reset to setup)", and a passkey troubleshooting entry (NotAllowedError / PRF / fingerprint verify-no-match). - README: add a "Passkey identity (advanced)" section linking the specs, add passkey.js/keyformat.js/auth-header-utils.js to the source tree, correct the test count to 169, and add a passkey troubleshooting note. Co-Authored-By: jjohare <github@thedreamlab.uk>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two robustness fixes surfaced while live-testing the 0.0.8 passkey identity flow. Source-only — CI rebuilds the bundles.
1. Content-script resilience to an invalidated extension context
src/injected.js,src/nip98-interceptor.jsWhen the extension is reloaded/updated/disabled while a consuming page stays open, the content script is orphaned: every
chrome.runtime.*call throwsExtension context invalidated.A high-frequency caller (observed on Proton, whoseeventManagerpolls continuously) then floods the console with an identical multi-line stack on every request.Fix: the bridge latches the dead context on first sight,
console.warns once, dispatchespodkey-nip98-disableso the page interceptor restores nativefetch/XHR (stops round-tripping to a dead extension), and answers all later requests with a silentnull. A tab reload re-injects fresh scripts against the live extension.chrome.runtime?.id(goesundefinedwhen orphaned) plus an error-message match (Extension context invalidated/message port closed/receiving end does not exist).2. Reset-to-init reachable from the main screen
popup/popup.html,popup/popup.js,popup/popup.csshandleForgetKey(wipe vault + public key + passkey config → return to setup) was only wired to the unlock screen's link. An unlocked user had no way back to the setup screen — which is the sole entry point for passkey-derived identity creation. So creating a passkey identity when a key already existed meant locking first, then "Forget key".Fix: a "Start over" footer link on the main screen, wired to the existing
handleForgetKey, styled with the existing--dangertoken. Same confirm-guarded wipe; no new backend surface.Verification
npm run build✓npm test→ 169/169 pass ✓npm run lint(eslint) → clean ✓src/…); bundles are gitignored and rebuilt by CI, so this PR is source-only by design.🤖 Generated by Claude Code