a205e1e3d989

add SUBMIT_FEEDBACK message type, handler, FEEDBACK_ENDPOINT constant, version bump to 2.1.0

time
2026-04-26 13:24 UTC · 6 months ago
machine
koh2
parent
e42e2b44e8f8
5 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.ts+31 −1src/shared/types.ts+1 −0
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.0.3",4+  "version": "2.1.0",55   "description": "Zero-knowledge password manager",66   "browser_specific_settings": {77     "gecko": {

view file

manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach",4-  "version": "2.0.3",4+  "version": "2.1.0",55   "description": "Zero-knowledge password manager",66   "action": {77     "default_popup": "src/popup/index.html",

view file

package.json+1 −1
@@ -1,6 +1,6 @@11 {22   "name": "peach",3-  "version": "2.0.3",3+  "version": "2.1.0",44   "description": "Zero-knowledge password manager",55   "type": "module",66   "scripts": {

view file

src/background/messages.ts+31 −1
@@ -29,6 +29,12 @@2929   { prefix: "192.168." },3030 ];3131 32+// Empty disables network submission while the UI continues to function as a33+// no-op (the handler returns ok:true without calling fetch). When set, the34+// URL is validated by `isAllowedCanaryWebhookUrl` before any request, so the35+// same private-IP/HTTPS rules that gate canary webhooks apply here.36+const FEEDBACK_ENDPOINT = "";37+3238 export function setupMessageHandler(): void {3339   chrome.runtime.onMessage.addListener(3440     (msg: unknown, sender, sendResponse) => {@@ -474,6 +480,29 @@474480         const declined = await vault.isCardDeclined(last4, expMonth, expYear);475481         return { ok: true, data: declined };476482       }483+      case "SUBMIT_FEEDBACK": {484+        const { category, message, version, browser } = msg.payload as {485+          category: string;486+          message: string;487+          version: string;488+          browser: string;489+        };490+        if (!message.trim()) return { ok: false, error: "message is empty" };491+        if (!FEEDBACK_ENDPOINT) return { ok: true };492+        if (!isAllowedCanaryWebhookUrl(FEEDBACK_ENDPOINT)) {493+          return { ok: false, error: "invalid feedback endpoint" };494+        }495+        try {496+          const res = await fetch(FEEDBACK_ENDPOINT, {497+            method: "POST",498+            headers: { "Content-Type": "application/json" },499+            body: JSON.stringify({ category, message, version, browser, source: "peach-extension" }),500+          });501+          return { ok: res.ok, error: res.ok ? undefined : `HTTP ${res.status}` };502+        } catch (err) {503+          return { ok: false, error: err instanceof Error ? err.message : "network error" };504+        }505+      }477506       default:478507         return { ok: false, error: "unknown message type" };479508     }@@ -508,7 +537,8 @@508537     type !== "GET_PENDING_PASSKEY" &&509538     type !== "GET_PASSKEY_PROVIDER_STATE" &&510539     type !== "DECLINE_CARD_SAVE" &&511-    type !== "IS_CARD_DECLINED"540+    type !== "IS_CARD_DECLINED" &&541+    type !== "SUBMIT_FEEDBACK"512542   );513543 }514544 

view file

src/shared/types.ts+1 −0
@@ -197,6 +197,7 @@197197   | "RECORD_MANUAL_SUMMON"198198   | "DECLINE_CARD_SAVE"199199   | "IS_CARD_DECLINED"200+  | "SUBMIT_FEEDBACK"200201   | "GET_VAULT_STATUS"201202   // Content-script-bound message types — sent BY the background TO content202203   // scripts. They never reach messages.ts's switch. Kept in this union so

view file