46fd698ce73c
fix: Restore legacy Chrome passkey assertions (v5.2.4)
- time
- 2026-09-06 19:32 UTC · 1 month ago
- machine
- koh2
- parent
- 0a1c5debb187
↓ peach-browser-46fd698c.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/passkey-chrome-ceremony.test.ts+21 −0src/background/passkey.ts+7 −1manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "5.2.3",4+ "version": "5.2.4",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -2,7 +2,7 @@22 "manifest_version": 3,33 "minimum_chrome_version": "116",44 "name": "Peach Password Manager",5- "version": "5.2.3",5+ "version": "5.2.4",66 "description": "Zero-knowledge password manager",77 "action": {88 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "5.2.3",3+ "version": "5.2.4",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",src/background/passkey-chrome-ceremony.test.ts+21 −0
@@ -579,6 +579,27 @@579579 expect(after!.passkey!.lastUsedAt).toBeDefined();580580 });581581 582+ it("get preserves the BE flag used to register legacy Chrome passkeys", async () => {583+ const vault = await import("./vault");584+ await vault.createVault("correct-pass-12345");585+ const { entry } = await seedPasskey("github.com");586+587+ expect(entry.passkey!.browser).toBe("chrome");588+ expect(entry.passkey!.backupEligible).toBe(false);589+590+ autoApprove();591+ fireGet({ rpId: "github.com", challenge: "Y2g", allowCredentials: [] }, 206);592+ const done = await waitForGetComplete(206);593+ const response = JSON.parse(done.responseJson!);594+ const authenticatorData = Uint8Array.from(595+ atob(response.response.authenticatorData.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(response.response.authenticatorData.length / 4) * 4, "=")),596+ (char) => char.charCodeAt(0),597+ );598+599+ expect(authenticatorData[32]! & 0x08).toBe(0x08);600+ expect(vault.getEntries().find((candidate) => candidate.id === entry.id)!.passkey!.backupEligible).toBe(true);601+ });602+582603 it("get passes through to platform when the stored passkey has no private key (Firefox-created)", async () => {583604 const vault = await import("./vault");584605 await vault.createVault("correct-pass-12345");src/background/passkey.ts+7 −1
@@ -730,7 +730,12 @@730730 }731731 732732 const nextSignCount = credential.signCount + 1;733- const flags = 0x05 | (credential.backupEligible ? 0x08 : 0) | (credential.backupState ? 0x10 : 0);733+ // Chrome passkeys have always been registered by Peach with BE=1 (0x4d),734+ // but versions before v5.0.87 incorrectly persisted backupEligible=false.735+ // WebAuthn requires BE to match registration, so repair that legacy metadata736+ // while constructing the assertion GitHub and other strict RPs verify.737+ const backupEligible = credential.browser === "chrome" ? true : credential.backupEligible;738+ const flags = 0x05 | (backupEligible ? 0x08 : 0) | (credential.backupState ? 0x10 : 0);734739 const authData = await buildAuthenticatorData({735740 rpId: credential.rpId,736741 flags,@@ -754,6 +759,7 @@754759 await vault.updateEntry(match.id, {755760 passkey: {756761 ...credential,762+ backupEligible,757763 signCount: nextSignCount,758764 lastUsedAt: Date.now(),759765 },