478a839aacae

delete the SUBMIT_FEEDBACK handler that returned ok while sending nothing, and the 261 lines of pairing-code CSS no component has referenced since the code-entry surface was removed (v4.2.7)

time
2026-07-26 17:43 UTC · 3 months ago
machine
koh2
agent
claude-opus-5
session
feedback wiring and dead-code cleanup
parent
c8a0fc89e74d
7 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/messages.test.ts+3 −36src/background/messages.ts+1 −33src/popup/styles/popup.css+0 −261src/shared/types.ts+0 −1
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "4.2.6",4+  "version": "4.2.7",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 Password Manager",4-  "version": "4.2.6",4+  "version": "4.2.7",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": "4.2.6",3+  "version": "4.2.7",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/messages.test.ts+3 −36
@@ -713,36 +713,6 @@713713     expect(fetchMock).not.toHaveBeenCalled();714714   });715715 716-  it("SUBMIT_FEEDBACK returns ok:true and skips network when FEEDBACK_ENDPOINT is empty", async () => {717-    const response = await dispatch({718-      type: "SUBMIT_FEEDBACK",719-      payload: {720-        category: "Bug report",721-        message: "the popup flashes",722-        version: "2.1.0",723-        browser: "Chrome",724-      },725-    });726-727-    expect(response).toMatchObject({ ok: true });728-    expect(fetchMock).not.toHaveBeenCalled();729-  });730-731-  it("SUBMIT_FEEDBACK returns ok:false when message is empty whitespace", async () => {732-    const response = await dispatch({733-      type: "SUBMIT_FEEDBACK",734-      payload: {735-        category: "Bug report",736-        message: "  ",737-        version: "2.1.0",738-        browser: "Chrome",739-      },740-    });741-742-    expect(response).toMatchObject({ ok: false, error: "message_empty" });743-    expect(fetchMock).not.toHaveBeenCalled();744-  });745-746716   it("GET_IDENTITIES when locked returns vault locked error", async () => {747717     const vault = await import("./vault");748718     await vault.createVault("correct-pass-12345");@@ -791,7 +761,7 @@791761     expect(hits[0]!.useCount).toBe(3);792762   });793763 794-  it("SUBMIT_FEEDBACK does not refresh the auto-lock timer", async () => {764+  it("IS_CARD_DECLINED does not refresh the auto-lock timer", async () => {795765     const vault = await import("./vault");796766     await vault.createVault("correct-pass-12345");797767     const alarmsCreate = chrome.alarms.create as unknown as ReturnType<typeof vi.fn>;@@ -801,12 +771,9 @@801771     await dispatch({ type: "GET_ENTRIES" });802772     expect(alarmsCreate).toHaveBeenCalled();803773 804-    // SUBMIT_FEEDBACK is in the exclusion list and must not re-arm774+    // Passive queries are in the exclusion list and must not re-arm805775     alarmsCreate.mockClear();806-    await dispatch({807-      type: "SUBMIT_FEEDBACK",808-      payload: { category: "Bug report", message: "hi", version: "2.1.0", browser: "Chrome" },809-    });776+    await dispatch({ type: "IS_CARD_DECLINED", payload: { origin: "https://example.com" } });810777     expect(alarmsCreate).not.toHaveBeenCalled();811778   });812779 

view file

src/background/messages.ts+1 −33
@@ -157,14 +157,6 @@157157 }158158 159159 // ---------------------------------------------------------------------------160-// Feedback submission target. Empty disables network submission while the UI161-// continues to function as a no-op (the handler returns ok:true without162-// calling fetch). When set, the URL is validated by163-// `isAllowedCanaryWebhookUrl` before any request.164-// ---------------------------------------------------------------------------165-166-const FEEDBACK_ENDPOINT = "";167-168160 // PCH-01-018: operations that irreversibly destroy or replace vault contents.169161 // These are gated to trusted extension-page senders in handleMessage; the170162 // confirmation UX otherwise lives only in the popup. Keep this in sync when@@ -1284,29 +1276,6 @@12841276         return { ok: true };12851277       }12861278 1287-      case "SUBMIT_FEEDBACK": {1288-        const { category, message, version, browser } = msg.payload as {1289-          category: string;1290-          message: string;1291-          version: string;1292-          browser: string;1293-        };1294-        if (!message.trim()) return { ok: false, error: "message_empty" };1295-        if (!FEEDBACK_ENDPOINT) return { ok: true };1296-        if (!isAllowedCanaryWebhookUrl(FEEDBACK_ENDPOINT)) {1297-          return { ok: false, error: "invalid_feedback_endpoint" };1298-        }1299-        try {1300-          const res = await fetch(FEEDBACK_ENDPOINT, {1301-            method: "POST",1302-            headers: { "Content-Type": "application/json" },1303-            body: JSON.stringify({ category, message, version, browser, source: "peach-extension" }),1304-          });1305-          return { ok: res.ok, error: res.ok ? undefined : `HTTP ${res.status}` };1306-        } catch (err) {1307-          return { ok: false, error: err instanceof Error ? err.message : "network_error" };1308-        }1309-      }13101279       // Android-only: biometric unlock with pre-derived key.13111280       case "UNLOCK_WITH_KEY": {13121281         const { masterKeyHex } = msg.payload as { masterKeyHex: string };@@ -1693,8 +1662,7 @@16931662     type !== "GET_PENDING_PASSKEY" &&16941663     type !== "GET_PASSKEY_PROVIDER_STATE" &&16951664     type !== "DECLINE_CARD_SAVE" &&1696-    type !== "IS_CARD_DECLINED" &&1697-    type !== "SUBMIT_FEEDBACK"1665+    type !== "IS_CARD_DECLINED"16981666   );16991667 }17001668 

view file

src/popup/styles/popup.css+0 −261
@@ -5198,205 +5198,6 @@51985198   margin-top: 8px;51995199 }52005200 5201-.peach-pairing-body {5202-  flex: 1;5203-  overflow-y: auto;5204-  display: flex;5205-  flex-direction: column;5206-}5207-5208-.peach-pairing-content {5209-  flex: 1;5210-  display: flex;5211-  flex-direction: column;5212-  align-items: center;5213-  justify-content: center;5214-  gap: 14px;5215-  padding: 28px 20px;5216-  text-align: center;5217-}5218-5219-.peach-pairing-code-screen {5220-  gap: 18px;5221-}5222-5223-.peach-pairing-headline {5224-  font-family: var(--font-display);5225-  font-style: italic;5226-  font-weight: 300;5227-  font-size: 28px;5228-  color: var(--peach-t0);5229-  margin: 0;5230-  line-height: 1;5231-}5232-5233-.peach-pairing-subline {5234-  font-size: 0.75rem;5235-  color: var(--peach-t2);5236-  max-width: 220px;5237-  line-height: 1.5;5238-  margin: 0;5239-}5240-5241-.peach-pairing-subline--center {5242-  text-align: center;5243-}5244-5245-/* 6-digit pairing code — both display (.peach-pairing-code) and entry5246-   (.peach-pairing-code-input) share IBM Plex Mono / 36px / wide tracking5247-   so the two modes feel like the same surface. */5248-.peach-pairing-code {5249-  font-family: "IBM Plex Mono", monospace;5250-  font-size: 36px;5251-  letter-spacing: 0.25em;5252-  color: var(--peach-t0);5253-  text-align: center;5254-  padding: 24px 0;5255-  text-shadow:5256-    0 0 24px color-mix(in srgb, var(--peach-accent) 22%, transparent),5257-    0 0 48px color-mix(in srgb, var(--peach-accent) 12%, transparent);5258-  background: transparent;5259-  border: 0;5260-  cursor: default;5261-  user-select: text;5262-}5263-5264-.peach-pairing-code--loading,5265-.peach-pairing-code--expired {5266-  font-size: 18px;5267-  letter-spacing: 0.04em;5268-  color: var(--peach-t2);5269-  cursor: pointer;5270-  text-shadow: none;5271-}5272-5273-.peach-pairing-qr-container {5274-  display: flex;5275-  flex-direction: column;5276-  align-items: center;5277-  gap: 10px;5278-}5279-5280-.peach-pairing-qr {5281-  width: 240px;5282-  height: 240px;5283-  display: block;5284-}5285-5286-.peach-pairing-instruction {5287-  font-size: 0.75rem;5288-  color: var(--peach-t2);5289-  text-align: center;5290-  line-height: 1.5;5291-  margin: 0;5292-  max-width: 220px;5293-}5294-5295-.peach-pairing-expiry {5296-  font-family: "IBM Plex Mono", monospace;5297-  font-size: 13px;5298-  letter-spacing: 0.06em;5299-  color: var(--peach-t2);5300-  margin: 0;5301-}5302-5303-.peach-pairing-regen {5304-  font-size: 0.75rem;5305-  color: var(--peach-accent);5306-  background: transparent;5307-  border: 0;5308-  cursor: pointer;5309-  padding: 4px 0;5310-  text-decoration: underline;5311-  text-underline-offset: 2px;5312-}5313-5314-.peach-pairing-code-input {5315-  font-family: "IBM Plex Mono", monospace;5316-  font-size: 36px;5317-  letter-spacing: 0.25em;5318-  color: var(--peach-t0);5319-  background: transparent;5320-  border: 0;5321-  border-bottom: 1px solid var(--peach-t3);5322-  outline: none;5323-  text-align: center;5324-  padding: 18px 0;5325-  width: 220px;5326-  caret-color: var(--peach-accent);5327-  transition: border-color 160ms ease;5328-}5329-5330-.peach-pairing-code-input::placeholder {5331-  color: var(--peach-t3);5332-}5333-5334-.peach-pairing-code-input:focus {5335-  border-bottom-color: var(--peach-accent);5336-}5337-5338-.peach-pairing-toggle {5339-  background: transparent;5340-  border: 0;5341-  color: var(--peach-t2);5342-  font-size: 0.75rem;5343-  padding: 8px 4px;5344-  cursor: pointer;5345-  transition: color 120ms ease;5346-}5347-5348-.peach-pairing-toggle:hover:not(:disabled) {5349-  color: var(--peach-t1);5350-}5351-5352-.peach-pairing-toggle:disabled {5353-  opacity: 0.5;5354-  cursor: default;5355-}5356-5357-.peach-pairing-hint {5358-  font-size: 0.6875rem;5359-  color: var(--peach-t2);5360-  margin: 0;5361-  text-align: center;5362-}5363-5364-.peach-pairing-status {5365-  display: flex;5366-  align-items: center;5367-  gap: 8px;5368-  margin: 0;5369-  font-size: 0.75rem;5370-  color: var(--peach-t1);5371-}5372-5373-.peach-pairing-error {5374-  margin: 0;5375-  font-size: 0.6875rem;5376-  color: var(--peach-breach);5377-}5378-5379-.peach-pairing-error--muted {5380-  color: var(--peach-t2);5381-}5382-5383-.peach-pairing-spinner {5384-  width: 12px;5385-  height: 12px;5386-  border: 1.5px solid var(--peach-t3);5387-  border-top-color: var(--peach-accent);5388-  border-radius: 50%;5389-  animation: peach-spin 0.8s linear infinite;5390-}5391-5392-.peach-pairing-success-icon,5393-.peach-pairing-error-icon,5394-.peach-pairing-hero {5395-  display: inline-flex;5396-  align-items: center;5397-  justify-content: center;5398-}5399-54005201 /* Tag chips */54015202 .peach-tag-chip {54025203   display: inline-flex;@@ -8740,68 +8541,6 @@87408541   color: var(--peach-t3);87418542   margin: 0;87428543   line-height: 1.5;8743-}8744-8745-/* ── Add Device — Android scan tabs ─────────────────────────────────────── */8746-8747-.peach-pairing-tabs {8748-  display: flex;8749-  border: 1px solid var(--peach-border);8750-  border-radius: 8px;8751-  overflow: hidden;8752-  margin-bottom: 4px;8753-}8754-8755-.peach-pairing-tab {8756-  flex: 1;8757-  padding: 10px 0;8758-  background: none;8759-  border: none;8760-  font-family: 'IBM Plex Mono', monospace;8761-  font-size: 11px;8762-  letter-spacing: 0.06em;8763-  color: var(--peach-t2);8764-  cursor: pointer;8765-  transition: background 150ms, color 150ms;8766-}8767-8768-.peach-pairing-tab.is-active {8769-  background: var(--peach-accent);8770-  color: #fff;8771-  font-weight: 600;8772-}8773-8774-.peach-pairing-tab:not(.is-active):active {8775-  background: var(--peach-border);8776-}8777-8778-/* Camera view */8779-.peach-pairing-camera-container {8780-  position: relative;8781-  width: 100%;8782-  aspect-ratio: 1;8783-  border-radius: 12px;8784-  overflow: hidden;8785-  background: #000;8786-  flex-shrink: 0;8787-}8788-8789-.peach-pairing-video {8790-  width: 100%;8791-  height: 100%;8792-  object-fit: cover;8793-}8794-8795-.peach-pairing-scan-frame {8796-  position: absolute;8797-  top: 50%;8798-  left: 50%;8799-  transform: translate(-50%, -50%);8800-  width: 60%;8801-  aspect-ratio: 1;8802-  border: 2px solid var(--peach-accent);8803-  border-radius: 8px;8804-  pointer-events: none;88058544 }88068545 88078546 /* ── Notes Mode ── */

view file

src/shared/types.ts+0 −1
@@ -330,7 +330,6 @@330330   | "RECORD_MANUAL_SUMMON"331331   | "DECLINE_CARD_SAVE"332332   | "IS_CARD_DECLINED"333-  | "SUBMIT_FEEDBACK"334333   | "GET_VAULT_STATUS"335334   | "GET_ADVANCED_HEALTH_REPORT"336335   | "DEACTIVATE_LICENSE"

view file