0b2b4a23a099

fix: complete PB-26 sender policy compatibility (v5.0.25)

time
2026-08-30 12:06 UTC · 1 month ago
machine
koh2
parent
0af21be3f7f9
6 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.ts+8 −6src/content/passkey-toast/passkey-toast.test.ts+1 −0src/popup/views/contracts.test.tsx+10 −2
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.0.22",4+  "version": "5.0.25",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.0.22",5+  "version": "5.0.25",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.0.22",3+  "version": "5.0.25",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/messages.ts+8 −6
@@ -244,12 +244,14 @@244244     // PB-26-016: sender authorization is an exhaustive policy, not a245245     // hand-maintained privileged denylist. A missing/unknown policy entry or a246246     // background-only message fails closed before any handler runs.247-    if (!isMessageSenderAllowed(248-      msg.type,249-      sender,250-      chrome.runtime.id,251-      chrome.runtime.getURL(""),252-    )) {247+    // Extension UI messages may legitimately omit sender.url. Resolve the248+    // browser-attested extension origin only when a URL is present; this also249+    // keeps test/runtime shims without getURL fail-closed for URL-bearing250+    // senders instead of throwing before policy evaluation.251+    const extensionOrigin = sender.url && typeof chrome.runtime.getURL === "function"252+      ? chrome.runtime.getURL("")253+      : "";254+    if (!isMessageSenderAllowed(msg.type, sender, chrome.runtime.id, extensionOrigin)) {253255       return { ok: false, error: "invalid_sender" };254256     }255257 

view file

src/content/passkey-toast/passkey-toast.test.ts+1 −0
@@ -24,6 +24,7 @@2424   const chromeMock = {2525     runtime: {2626       id: 'peach-extension',27+      getURL: (path: string) => `chrome-extension://peach-extension/${path}`,2728       sendMessage: vi.fn(async () => ({ ok: true })),2829       onMessage: {2930         addListener: vi.fn((fn: MessageListener) => {

view file

src/popup/views/contracts.test.tsx+10 −2
@@ -240,7 +240,11 @@240240 241241   it("Lock uses a configured preferred PIN and keeps the password fallback available", async () => {242242     sendMessageMock.mockImplementation(async (msg: unknown) => {243-      return (msg as { type: string }).type === "GET_SETTINGS"243+      const type = (msg as { type: string }).type;244+      if (type === "GET_PIN_STATUS") {245+        return { ok: true, data: { configured: true, available: true, attemptsRemaining: 3 } };246+      }247+      return type === "GET_SETTINGS"244248         ? { ok: true, data: { pinEnabled: true, pinPreferred: true } }245249         : { ok: true };246250     });@@ -262,7 +266,11 @@262266 263267   it("places the PIN method switch below the unlock button", async () => {264268     sendMessageMock.mockImplementation(async (msg: unknown) => {265-      return (msg as { type: string }).type === "GET_SETTINGS"269+      const type = (msg as { type: string }).type;270+      if (type === "GET_PIN_STATUS") {271+        return { ok: true, data: { configured: true, available: true, attemptsRemaining: 3 } };272+      }273+      return type === "GET_SETTINGS"266274         ? { ok: true, data: { pinEnabled: true, pinPreferred: false } }267275         : { ok: true };268276     });

view file