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
↓ peach-browser-478a839a.tar.gzatlas at this save
files changed7 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 −1manifest.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": {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",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",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 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 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 ── */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"