52a1b1bfa47f

enable passkey interception by default with saved opt-out (v5.3.8)

time
2026-10-08 17:32 UTC · 2 weeks ago
machine
Junes-MacBook-Pro.local
agent
gpt-6
session
reliable firefox passkey sign-in
parent
2627a8b30c10
6 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/passkey-firefox-proxy.test.ts+20 −0src/background/passkey.ts+5 −5src/popup/views/Settings.tsx+1 −1
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.3.7",4+  "version": "5.3.8",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

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.3.7",5+  "version": "5.3.8",66   "description": "Zero-knowledge password manager",77   "action": {88     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "5.3.7",3+  "version": "5.3.8",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/passkey-firefox-proxy.test.ts+20 −0
@@ -141,6 +141,26 @@141141     void wait();142142   }143143 144+  it.each([[undefined, true], [true, true], [false, false]] as const)("defaults passkey interception on while preserving %s", async (preference, enabled) => {145+    storage.peach_settings = { breachMonitoring: false, ...(preference === undefined ? {} : { passkeyProviderEnabled: preference }) };146+    vi.stubGlobal("navigator", { userAgent: "Mozilla/5.0 Firefox/157.0" });147+    const passkey = await import("./passkey");148+    await passkey.setupPasskeyProxy();149+    const state = await passkey.getPasskeyProviderState();150+    expect(state).toMatchObject({ supported: true, enabled, attached: enabled });151+  });152+153+  it.each(["PASSKEY_HAS_CREDENTIALS", "PASSKEY_GET", "PASSKEY_CREATE"] as const)("honors explicit disabled interception for %s", async (type) => {154+    const vault = await import("./vault");155+    await vault.createVault("correct-pass-12345");156+    await vault.updateSettings({ passkeyProviderEnabled: false });157+    await expect(dispatch({158+      type,159+      payload: { rpId: "github.com", userName: "june", userId: "AQID", challenge: "x", origin: "https://github.com", clientDataJSON: Array.from(new TextEncoder().encode("{}")), allowCredentials: [] },160+    })).resolves.toMatchObject({ ok: false, error: "not_applicable" });161+    expect(chrome.action.openPopup).not.toHaveBeenCalled();162+  });163+144164   it("PASSKEY_HAS_CREDENTIALS returns false when vault has no passkey for rpId", async () => {145165     const vault = await import("./vault");146166     await vault.createVault("correct-pass-12345");

view file

src/background/passkey.ts+5 −5
@@ -295,7 +295,7 @@295295 export async function getPasskeyProviderState(): Promise<PasskeyProviderState> {296296   const settings = await vault.ensureSettingsLoaded();297297   const supported = isPasskeySupported();298-  const enabled = settings.passkeyProviderEnabled === true;298+  const enabled = settings.passkeyProviderEnabled !== false;299299   return {300300     supported,301301     enabled,@@ -377,7 +377,7 @@377377 378378 async function refreshPasskeyProxy(): Promise<void> {379379   const settings = await vault.ensureSettingsLoaded();380-  if (settings.passkeyProviderEnabled === true) {380+  if (settings.passkeyProviderEnabled !== false) {381381     await attachPasskeyProxy();382382     return;383383   }@@ -1106,7 +1106,7 @@11061106   payload: FirefoxPasskeyHasCredentialsPayload,11071107   callerOrigin?: string,11081108 ): Promise<{ ok: true; hasCredentials: boolean } | { ok: false; error: string }> {1109-  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY) {1109+  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY || (await vault.ensureSettingsLoaded()).passkeyProviderEnabled === false) {11101110     return { ok: false, error: "not_applicable" };11111111   }11121112   // Scope the existence check to the caller's own origin so an arbitrary page@@ -1171,7 +1171,7 @@11711171   payload: FirefoxPasskeyCreatePayload,11721172   callerOrigin?: string,11731173 ): Promise<FirefoxPasskeyResult<FirefoxCreateCredentialResponse>> {1174-  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY) {1174+  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY || (await vault.ensureSettingsLoaded()).passkeyProviderEnabled === false) {11751175     return { ok: false, error: "not_applicable" };11761176   }11771177   // WebAuthn §7.1 step 6 — the requested rpId must be owned by the page's@@ -1271,7 +1271,7 @@12711271   payload: FirefoxPasskeyGetPayload,12721272   callerOrigin?: string,12731273 ): Promise<FirefoxPasskeyResult<FirefoxGetCredentialResponse>> {1274-  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY) {1274+  if (!FIREFOX_USE_CONTENT_SCRIPT_PROXY || (await vault.ensureSettingsLoaded()).passkeyProviderEnabled === false) {12751275     return { ok: false, error: "not_applicable" };12761276   }12771277   // WebAuthn §7.2 step 8 — the rpId must be owned by the page's browser-attested

view file

src/popup/views/Settings.tsx+1 −1
@@ -1449,7 +1449,7 @@14491449             <div class="peach-settings-row-main">14501450               <span>Intercept passkey requests</span>14511451               <span class="peach-settings-value" style="font-size:11px;line-height:1.5;color:var(--t2)">1452-                Peach can handle passkey sign-in and creation on supported Chromium browsers.1452+                Use Peach for passkey sign-in and creation in Chrome and Firefox.14531453               </span>14541454             </div>14551455             <button

view file