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
↓ peach-browser-ee7fdbb0.tar.gzatlas at this save
files changed8 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 −6manifest.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": {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",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",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 {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();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"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(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>