ab5496be14e8

fix passkey Google origin timing bug and passkey+TOTP real-time merge

time
2026-05-31 01:04 UTC · 4 months ago
machine
koh2
agent
claude-sonnet-4-6
session
passkey Google origin and TOTP merge
parent
a885fa9c118a
6 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.ts+3 −0src/background/passkey.ts+15 −1src/background/vault.ts+14 −0
manifest.firefox.json+1 −1
@@ -2,7 +2,7 @@22   "_comment_audio_capture": "Firefox does not honor the Chrome 'audioCapture' optional_permission — getUserMedia in WebExtensions is gated solely by the runtime permission prompt. Microphone access for chirp pairing works from the popup under the existing '<all_urls>' host permission; no manifest entry is required or accepted here.",33   "manifest_version": 3,44   "name": "Peach Password Manager",5-  "version": "3.6.142",5+  "version": "3.6.143",66   "description": "Zero-knowledge password manager",77   "browser_specific_settings": {88     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "3.6.142",4+  "version": "3.6.143",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "3.6.141",3+  "version": "3.6.143",44   "description": "Zero-knowledge password manager",55   "type": "module",66   "scripts": {

view file

src/background/messages.ts+3 −0
@@ -365,6 +365,9 @@365365           return { ok: false, error: "invalid_payload" };366366         }367367         const entry = await vault.addEntry(payload as Parameters<typeof vault.addEntry>[0]);368+        // Merge any same-domain passkey entry with this new entry right away369+        // (e.g. user adds a TOTP for a site that already has a passkey entry).370+        void vault.consolidatePasskeyEntries();368371         return { ok: true, data: entry };369372       }370373       case "BATCH_ADD_ENTRIES": {

view file

src/background/passkey.ts+15 −1
@@ -428,6 +428,14 @@428428     return;429429   }430430 431+  // Capture the page origin NOW — before any popup opens. Once the extension432+  // action popup fires, it can steal lastFocusedWindow so the tabs query433+  // returns no results and falls back to https://<rpId>. For sites where the434+  // page origin is a subdomain of the rpId (e.g. myaccount.google.com vs435+  // rpId google.com) that fallback produces the wrong origin and the RP436+  // rejects the attestation with "Something went wrong".437+  const pageOrigin = await resolvePageOrigin(rpId);438+431439   if (!PASSKEY_CREATE_E2E_BYPASS && !(await isProUser())) {432440     console.warn("[Peach passkey] reject: user is not Pro");433441     await rejectCreate(@@ -520,7 +528,7 @@520528   const clientDataJSON = buildClientDataJSON(521529     "webauthn.create",522530     options.challenge,523-    await resolvePageOrigin(rpId)531+    pageOrigin524532   );525533 526534   const passkey: PasskeyData = {@@ -556,6 +564,10 @@556564       passkey,557565     });558566   }567+  // Merge any same-domain TOTP-only entries into the passkey entry right now568+  // so the user sees one consolidated entry rather than waiting until next569+  // unlock for the decodePayload merge pass to run.570+  await vault.consolidatePasskeyEntries();559571 560572   try {561573     await chrome.webAuthenticationProxy.completeCreateRequest({@@ -898,6 +910,7 @@898910       passkey,899911     });900912   }913+  await vault.consolidatePasskeyEntries();901914 902915   if (chrome.storage.session) {903916     await chrome.storage.session.remove(FIREFOX_PENDING_KEY);@@ -1199,6 +1212,7 @@11991212       passkey,12001213     });12011214   }1215+  await vault.consolidatePasskeyEntries();12021216 12031217   return {12041218     ok: true,

view file

src/background/vault.ts+14 −0
@@ -1633,6 +1633,20 @@16331633   return nextEntry;16341634 }16351635 1636+/**1637+ * Run the passkey-merge pass on the live in-memory entries and persist if1638+ * anything changed. Called immediately after any passkey registration so that1639+ * a same-domain TOTP-only entry already in the vault gets consolidated right1640+ * away instead of waiting until the next lock/unlock cycle.1641+ */1642+export async function consolidatePasskeyEntries(): Promise<void> {1643+  if (!derivedKey) return;1644+  const { merged } = mergePasskeyOnlyIntoLogins(entries);1645+  if (merged) {1646+    await persistEntries();1647+  }1648+}1649+16361650 export async function updateEntry(16371651   id: string,16381652   patch: Partial<VaultEntry>

view file