22d6a1a0bb03
fix: apply capDeviceName to adoption-sourced PairedDevice records (audit PB-26-603, v5.1.13)
- time
- 2026-09-06 14:59 UTC · 1 month ago
- machine
- koh2
- agent
- openrouter/tencent/hy4-preview
- session
- PB-26-601..611 audit closeout
- parent
- c067510e1a14
↓ peach-browser-22d6a1a0.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/shared/vault-adopt.test.ts+62 −0src/shared/vault-adopt.ts+3 −3manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "5.1.12",4+ "version": "5.1.13",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.1.12",5+ "version": "5.1.13",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.1.12",3+ "version": "5.1.13",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",src/shared/vault-adopt.test.ts+62 −0
@@ -865,3 +865,65 @@865865 expect(legacyCombinedSize).toBeGreaterThan(CEILING);866866 });867867 });868+869+/**870+ * PB-26-603 — adoption frames carry a peer-supplied `device_name` straight into871+ * `chrome.storage.local`. The manifest path caps it at 64 chars; adoption did872+ * not, so one name could be ~16Kx larger than the manifest bound.873+ */874+describe("PB-26-603 adoption device_name cap", () => {875+ it("caps a 500-char peer device_name to 64 chars on both PairedDevice records", async () => {876+ const longName = "X".repeat(500);877+ const [receiverChannel, sourceChannel] = memoryPair();878+ const rootKeyHex = "13".repeat(32);879+ const vaultId = await computeVaultId(Uint8Array.from(Buffer.from(rootKeyHex, "hex")));880+ const receiverUpsert = vi.fn();881+ const sourceUpsert = vi.fn();882+883+ const receiverDeps: AdoptionReceiverDeps = {884+ deviceName: "receiver",885+ generateDeviceId: () => "receiver-ephemeral",886+ confirmSas: vi.fn(async () => true),887+ createVaultFromRootKey: vi.fn(async () => ({ vaultId })),888+ deriveLocalIdentity: vi.fn(async () => ({889+ deviceId: "receiver-id",890+ deviceName: longName,891+ deviceType: "extension" as const,892+ longTermPublicKeyHex: "ab".repeat(32),893+ signingPublicKeyHex: "cd".repeat(32),894+ })),895+ upsertPairedDevice: receiverUpsert,896+ applyLicense: vi.fn(),897+ onError: vi.fn(),898+ };899+ const sourceDeps: AdoptionSourceDeps = {900+ sourceIdentity: {901+ deviceId: "source-id",902+ deviceName: longName,903+ deviceType: "extension" as const,904+ longTermPublicKeyHex: "ef".repeat(32),905+ signingPublicKeyHex: "01".repeat(32),906+ },907+ rootKeyHex: vi.fn(async () => rootKeyHex),908+ vaultId: vi.fn(async () => vaultId),909+ license: vi.fn(async () => "PPK-test"),910+ onConsent: vi.fn(async () => true),911+ upsertPairedDevice: sourceUpsert,912+ };913+914+ await Promise.all([915+ requestAdoption(receiverChannel, receiverDeps),916+ (async () => {917+ const request = JSON.parse(918+ new TextDecoder().decode(await sourceChannel.receive()),919+ ) as AdoptRequest;920+ await grantAdoption(sourceChannel, request, sourceDeps);921+ })(),922+ ]);923+924+ const storedReceiver = receiverUpsert.mock.calls[0]?.[0] as { deviceName: string };925+ const storedSource = sourceUpsert.mock.calls[0]?.[0] as { deviceName: string };926+ expect(storedReceiver.deviceName).toBe(longName.slice(0, 64));927+ expect(storedSource.deviceName).toBe(longName.slice(0, 64));928+ });929+});src/shared/vault-adopt.ts+3 −3
@@ -1,4 +1,4 @@1-import { SYNC_LIMITS } from "./sync-limits";1+import { capDeviceName, SYNC_LIMITS } from "./sync-limits";22 import { computeVaultId } from "./sync-identity";33 import type { DeviceType, PairedDevice, SignedDeviceManifest } from "./sync-types";44 import type { LocalIdentity, PairingTransport } from "./pairing-handshake";@@ -651,7 +651,7 @@651651 652652 const sourceDevice: PairedDevice = {653653 deviceId: frame.source.device_id,654- deviceName: frame.source.device_name,654+ deviceName: capDeviceName(frame.source.device_name),655655 deviceType: frame.source.device_type,656656 longTermPublicKeyHex: frame.source.long_term_public_key_hex,657657 signingPublicKeyHex: frame.source.signing_public_key_hex,@@ -720,7 +720,7 @@720720 721721 const device: PairedDevice = {722722 deviceId: identity.device_id,723- deviceName: identity.device_name,723+ deviceName: capDeviceName(identity.device_name),724724 deviceType: identity.device_type,725725 longTermPublicKeyHex: identity.long_term_public_key_hex,726726 signingPublicKeyHex: identity.signing_public_key_hex,