0555937cf5da

fix: randomize Chrome web-accessible chunk URLs and assert scoped hashed Firefox resources (v5.0.82)

time
2026-09-03 23:41 UTC · 1 month ago
machine
koh2
agent
claude-sonnet-4-6
session
PB-26-314 stable chunk URLs
parent
1c0220b12de9
5 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1scripts/web-accessible-resources.test.ts+40 −0vite.config.ts+16 −1
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.0.81",4+  "version": "5.0.82",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.81",5+  "version": "5.0.82",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.81",3+  "version": "5.0.82",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

scripts/web-accessible-resources.test.ts+40 −0
@@ -0,0 +1,40 @@1+import { readFileSync } from "node:fs";2+import { resolve } from "node:path";3+import { describe, expect, it } from "vitest";4+5+type WebAccessibleResource = {6+  matches: string[];7+  resources: string[];8+  use_dynamic_url?: boolean;9+};10+11+type ExtensionManifest = {12+  web_accessible_resources?: WebAccessibleResource[];13+};14+15+function readManifest(target: "chrome" | "firefox"): ExtensionManifest {16+  const directory = target === "chrome" ? "dist-chrome" : "dist-firefox";17+  return JSON.parse(18+    readFileSync(resolve(process.cwd(), directory, "manifest.json"), "utf8"),19+  ) as ExtensionManifest;20+}21+22+describe("shipped web-accessible resources", () => {23+  it("uses session-randomized URLs for Chrome content-script resources", () => {24+    const resources = readManifest("chrome").web_accessible_resources ?? [];25+26+    expect(resources).toHaveLength(1);27+    expect(resources[0]?.use_dynamic_url).toBe(true);28+    expect(resources[0]?.matches).toEqual(["<all_urls>"]);29+    expect(resources[0]?.resources.length).toBeGreaterThan(0);30+  });31+32+  it("keeps Firefox resources limited to content-script chunks with content hashes", () => {33+    const resources = readManifest("firefox").web_accessible_resources ?? [];34+    const files = resources.flatMap((entry) => entry.resources);35+36+    expect(files.length).toBeGreaterThan(0);37+    expect(files.every((file) => /^assets\/[^/]+-[A-Za-z0-9_-]+\.(?:js|css)$/.test(file))).toBe(true);38+    expect(files.every((file) => !file.includes("<dynamic_resource>"))).toBe(true);39+  });40+});

view file

vite.config.ts+16 −1
@@ -1,12 +1,19 @@11 import { defineConfig } from "vite";22 import solidPlugin from "vite-plugin-solid";33 import { crx } from "@crxjs/vite-plugin";4-import { copyFileSync, mkdirSync, readFileSync } from "fs";4+import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from "fs";55 import { resolve } from "path";66 77 const target = process.env.BUILD_TARGET || "chrome";88 const manifestPath = target === "firefox" ? "./manifest.firefox.json" : "./manifest.json";99 const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));10+if (target === "chrome") {11+  manifest.web_accessible_resources = [{12+    matches: ["<all_urls>"],13+    resources: ["<dynamic_resource>"],14+    use_dynamic_url: true,15+  }];16+}1017 const passkeyE2E = process.env.PEACH_E2E_PASSKEYS === "1";1118 const outDir = target === "firefox" ? "dist-firefox" : "dist-chrome";1219 @@ -22,6 +29,14 @@2229       resolve("node_modules/pdfjs-dist/build/pdf.worker.min.mjs"),2330       resolve(outDir, "pdf.worker.min.mjs"),2431     );32+    if (target === "chrome") {33+      const outputManifest = resolve(outDir, "manifest.json");34+      const builtManifest = JSON.parse(readFileSync(outputManifest, "utf8"));35+      for (const resource of builtManifest.web_accessible_resources ?? []) {36+        resource.use_dynamic_url = true;37+      }38+      writeFileSync(outputManifest, `${JSON.stringify(builtManifest, null, 2)}\n`);39+    }2540   },2641 };2742 

view file