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
↓ peach-browser-ab5496be.tar.gzatlas at this save
files changed6 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 −0manifest.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": {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",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": {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": {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,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>