ee7fdbb0ce28

fix: keep pairing consent on the 8-digit safety code (v5.2.14)

time
2026-09-07 13:19 UTC · 1 month ago
machine
koh2
agent
gpt-5
session
pairing consent correction
parent
62374dc19cf9
8 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/relay-adoption-bg.ts+3 −17src/popup/views/AdoptVaultView.test.tsx+2 −3src/popup/views/AdoptVaultView.tsx+4 −7src/popup/views/PairDevice.test.tsx+1 −2src/popup/views/PairDevice.tsx+3 −6
manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22   "manifest_version": 3,33   "name": "Peach Password Manager",4-  "version": "5.2.13",4+  "version": "5.2.14",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.2.13",5+  "version": "5.2.14",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.2.13",3+  "version": "5.2.14",44   "description": "Zero-knowledge password manager",55   "license": "GPL-3.0-only",66   "type": "module",

view file

src/background/relay-adoption-bg.ts+3 −17
@@ -280,7 +280,6 @@280280         adoptRequest,281281         derivePairingSAS(session.handshakeHash),282282         crypto.randomUUID(),283-        session.handshakeHash,284283       ),285284       upsertPairedDevice: storeAdoptedDevice,286285     });@@ -409,7 +408,7 @@409408       async confirmSas() {410409         const sas = derivePairingSAS(session.handshakeHash);411410         const id = crypto.randomUUID();412-        return waitForReceiverSasConfirmation(id, sas, session.handshakeHash);411+        return waitForReceiverSasConfirmation(id, sas);413412       },414413       async createVaultFromRootKey(rootKeyHex) {415414         // Direct call, not chrome.runtime.sendMessage — a service worker@@ -589,14 +588,9 @@589588  * the deferred the moment it sees the SAS push, and a missing slot would590589  * drop that approval on the floor.591590  */592-function pairingSessionFingerprint(handshakeHash: Uint8Array): string {593-  return bytesToHex(handshakeHash).slice(0, 12).match(/.{4}/g)?.join(" ") ?? "";594-}595-596591 function waitForReceiverSasConfirmation(597592   id: string,598593   sas: string,599-  handshakeHash: Uint8Array,600594 ): Promise<boolean> {601595   return new Promise<boolean>((resolve) => {602596     const timer = setTimeout(() => {@@ -607,12 +601,7 @@607601       clearTimeout(timer);608602       resolve(ok);609603     } });610-    push("ADOPTION_SOURCE_SAS", {611-      id,612-      sas,613-      displayOnly: false,614-      peerFingerprint: pairingSessionFingerprint(handshakeHash),615-    });604+    push("ADOPTION_SOURCE_SAS", { id, sas, displayOnly: false });616605   });617606 }618607 @@ -620,7 +609,6 @@620609   id: string,621610   request: AdoptRequest,622611   sas: string,623-  handshakeHash: Uint8Array,624612 ): Promise<boolean> {625613   return new Promise<boolean>((resolve) => {626614     const timer = setTimeout(() => {@@ -637,7 +625,6 @@637625       id,638626       sas,639627       receiverDeviceName: request.device_name,640-      peerFingerprint: pairingSessionFingerprint(handshakeHash),641628     });642629   });643630 }@@ -652,9 +639,8 @@652639   request: AdoptRequest,653640   sas: string,654641   id: string,655-  handshakeHash: Uint8Array,656642 ): Promise<boolean> {657-  return waitForSourceSasConfirmation(id, request, sas, handshakeHash);643+  return waitForSourceSasConfirmation(id, request, sas);658644 }659645 660646 function clearState(): void {

view file

src/popup/views/AdoptVaultView.test.tsx+2 −3
@@ -224,16 +224,15 @@224224           id: "receiver-sas-id",225225           sas: "48219371",226226           displayOnly: false,227-          peerFingerprint: "a1b2 c3d4 e5f6",228227         },229228       });230229     }231230     await flushView();232231 233232     expect(view.container.textContent).toContain("48219371");234-    expect(view.container.textContent).toContain("Confirm this code and session ID");235-    expect(view.container.textContent).toContain("a1b2 c3d4 e5f6");233+    expect(view.container.textContent).toContain("Confirm this 8-digit code");236234     expect(view.container.textContent).toContain("complete copy of its vault");235+    expect(view.container.textContent).not.toContain("session ID");237236     expect(button(view.container, "Confirm code")).toBeTruthy();238237     expect(view.container.querySelector(".peach-adoption-sas")).toBeTruthy();239238     expect(view.container.querySelector(".peach-pair-qr")).toBeNull();

view file

src/popup/views/AdoptVaultView.tsx+4 −7
@@ -58,7 +58,6 @@5858   const [strengthScore, setStrengthScore] = createSignal<number | null>(null);5959   const [receiverInvitation, setReceiverInvitation] = createSignal("");6060   const [receiverSas, setReceiverSas] = createSignal("");61-  const [peerFingerprint, setPeerFingerprint] = createSignal("");6261   const [receiverError, setReceiverError] = createSignal("");6362   const [receiverComplete, setReceiverComplete] = createSignal(false);6463   let completionTimer: number | undefined;@@ -116,13 +115,11 @@116115           id?: string;117116           sas?: string;118117           displayOnly?: boolean;119-          peerFingerprint?: string;120118         } | undefined;121119         if (p?.displayOnly === false && typeof p.sas === "string" && typeof (p as { id?: unknown }).id === "string") {122120           setReceiverSas(p.sas);123121           setReceiverSasId((p as { id: string }).id);124122           setReceiverSasDecision(false);125-          setPeerFingerprint(typeof p.peerFingerprint === "string" ? p.peerFingerprint : "");126123         }127124       } else if (msg?.type === "ADOPTION_SOURCE_RESULT") {128125         const p = msg.payload as {@@ -311,10 +308,10 @@311308                       <strong>{receiverSas()}</strong>312309                     </div>313310                     <p class="peach-adopt-confirmation-help">314-                      Confirm this code and session ID {peerFingerprint()} match315-                      the phone you intend to trust. Approving replaces this316-                      empty device with a complete copy of its vault, including317-                      existing passwords, passkeys, notes, and recovery access.311+                      Confirm this 8-digit code matches the phone you intend to312+                      trust. Approving replaces this empty device with a complete313+                      copy of its vault, including existing passwords, passkeys,314+                      notes, and recovery access.318315                     </p>319316                     <button320317                       class="peach-btn peach-btn--accent peach-btn--md"

view file

src/popup/views/PairDevice.test.tsx+1 −2
@@ -146,13 +146,12 @@146146       id: "test-sas-id",147147       sas: "48219371",148148       receiverDeviceName: "June's phone",149-      peerFingerprint: "a1b2 c3d4 e5f6",150149     });151150     expect(container.textContent).toContain("June's phone");152151     expect(container.textContent).toContain("48219371");153152     expect(container.textContent).toContain("Compare the 8-digit safety code");154-    expect(container.textContent).toContain("a1b2 c3d4 e5f6");155153     expect(container.textContent).toContain("complete copy of this vault");154+    expect(container.textContent).not.toContain("Session ID");156155     expect(container.querySelector("#adoption-consent-password")).toBeNull();157156     // The pop-up must NOT auto-approve; it waits for the user to tap a button.158157     expect(mockSendMessage).not.toHaveBeenCalledWith(

view file

src/popup/views/PairDevice.tsx+3 −6
@@ -41,7 +41,6 @@4141   const [sourceSas, setSourceSas] = createSignal("");4242   const [pendingSasId, setPendingSasId] = createSignal("");4343   const [receiverName, setReceiverName] = createSignal("New device");44-  const [peerFingerprint, setPeerFingerprint] = createSignal("");4544   const [shareError, setShareError] = createSignal("");4645   const [changingRelay, setChangingRelay] = createSignal(false);4746 @@ -106,7 +105,6 @@106105             id?: string;107106             sas?: string;108107             receiverDeviceName?: string;109-            peerFingerprint?: string;110108           } | undefined;111109           if (typeof p?.sas === "string") {112110             setSourceSas(p.sas);@@ -116,7 +114,6 @@116114                 ? p.receiverDeviceName117115                 : "New device",118116             );119-            setPeerFingerprint(typeof p.peerFingerprint === "string" ? p.peerFingerprint : "");120117             setSharePhase("sas");121118           }122119         } else if (msg?.type === "ADOPTION_SOURCE_RESULT") {@@ -283,9 +280,9 @@283280           <div class="peach-pair-headline">Compare the 8-digit safety code</div>284281           <div class="peach-pair-sub">285282             If {receiverName()} shows the same code, tap “They match” on that286-            device too. Session ID {peerFingerprint()}. Approving gives that287-            device a complete copy of this vault, including existing passwords,288-            passkeys, notes, and recovery access.283+            device too. Approving gives that device a complete copy of this284+            vault, including existing passwords, passkeys, notes, and recovery285+            access.289286           </div>290287           <div class="peach-adoption-sas" aria-label="Pairing confirmation code">291288             <strong>{sourceSas()}</strong>

view file