2c0d1e890d44
add unified cross-client sync protocol spec in docs/sync-protocol.md
- time
- 2026-09-08 21:46 UTC · 1 month ago
- machine
- koh2
- agent
- hf:zai-org/GLM-5.2
- session
- sync protocol unification
- parent
- 95e2413471dd
↓ peach-browser-2c0d1e89.tar.gzatlas at this save
files changed5 files
package.json+1 −1src/background/sync-vault-adapter.ts+11 −4src/shared/device-manifest.test.ts+1 −0src/shared/device-manifest.ts+5 −0src/shared/sync-types.ts+6 −1package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "5.2.21",3+ "version": "5.2.22",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",src/background/sync-vault-adapter.ts+11 −4
@@ -69,10 +69,11 @@6969 import { recordSyncAlerts } from "./sync-alerts";7070 import { SYNC_LIMITS, clampSyncTimestamp } from "../shared/sync-limits";7171 import type { VaultEntry } from "../shared/types";72-import type {73- ManifestDeviceEntry,74- PairedDevice,75- SignedDeviceManifest,72+import {73+ MAX_VOUCH_DEPTH,74+ type ManifestDeviceEntry,75+ type PairedDevice,76+ type SignedDeviceManifest,7677 } from "../shared/sync-types";7778 import { replaceLockedSyncSpool, drainLockedSyncInbox } from "./locked-sync-spool";7879 @@ -293,6 +294,7 @@293294 wsPort: device.wsPort,294295 relayUrl: device.relayUrl,295296 pairedAt: device.pairedAt,297+ vouchDepth: device.vouchDepth ?? 0,296298 };297299 }298300 @@ -329,6 +331,7 @@329331 issuer.trustSource !== "direct" &&330332 issuer.trustSource !== "vouched"331333 ) ||334+ (issuer.vouchDepth ?? 0) >= MAX_VOUCH_DEPTH ||332335 !issuer.signingPublicKeyHex ||333336 !/^[0-9a-f]{64}$/.test(issuer.signingPublicKeyHex)334337 ) {@@ -402,6 +405,9 @@402405 if (await isDeviceRevoked(entry.deviceId, entry.longTermPublicKeyHex)) {403406 continue;404407 }408+ if ((entry.vouchDepth ?? 0) > (issuer.vouchDepth ?? 0) + 1) {409+ continue;410+ }405411 const existing = await findPairedDeviceById(entry.deviceId);406412 const meshRoute = deriveManifestMeshRoute(407413 masterKey,@@ -426,6 +432,7 @@426432 relayUrl: meshRoute.relayUrl,427433 pairedAt: entry.pairedAt,428434 trustSource: "vouched",435+ vouchDepth: (issuer.vouchDepth ?? 0) + 1,429436 });430437 // PB-26-213: the secret bypasses the public registry into the431438 // encrypted pair-secret record.src/shared/device-manifest.test.ts+1 −0
@@ -25,6 +25,7 @@2525 signingPublicKeyHex: "b".repeat(64),2626 relayUrl: "wss://relay.peachpasswords.com",2727 pairedAt: 1_700_000_000_000,28+ vouchDepth: 0,2829 };2930 }3031 src/shared/device-manifest.ts+5 −0
@@ -26,6 +26,7 @@2626 import {2727 DEVICE_MANIFEST_FRESHNESS_MS,2828 DEVICE_MANIFEST_VERSION,29+ MAX_VOUCH_DEPTH,2930 type DeviceManifestBody,3031 type DeviceRevocation,3132 type ManifestDeviceEntry,@@ -151,6 +152,9 @@151152 if (typeof d.signingPublicKeyHex !== "string" || d.signingPublicKeyHex.length !== 64) {152153 throw new DeviceManifestError("malformed", "device.signingPublicKeyHex invalid");153154 }155+ if (d.vouchDepth != null && (!Number.isInteger(d.vouchDepth) || d.vouchDepth < 0 || d.vouchDepth > MAX_VOUCH_DEPTH)) {156+ throw new DeviceManifestError("malformed", "device.vouchDepth invalid");157+ }154158 if (155159 d.wsPort != null &&156160 (@@ -217,6 +221,7 @@217221 longTermPublicKeyHex: d.longTermPublicKeyHex.toLowerCase(),218222 signingPublicKeyHex: d.signingPublicKeyHex.toLowerCase(),219223 pairedAt: d.pairedAt,224+ vouchDepth: d.vouchDepth ?? 0,220225 };221226 if (d.wsPort != null) normalised.wsPort = d.wsPort;222227 if (d.relayUrl != null) normalised.relayUrl = normalizeRelayUrl(d.relayUrl);src/shared/sync-types.ts+6 −1
@@ -51,6 +51,8 @@5151 signingPublicKeyHex?: string;5252 /** v2 brief §4.2 — distinguishes direct-paired vs vouched-via-manifest. */5353 trustSource?: TrustSource;54+ /** Number of vouching edges from a directly paired device. */55+ vouchDepth?: number;5456 /**5557 * The peer's WebSocket sync port. Current Android hosts use fixed port 491425658 * and announce it inside the encrypted pairing channel.@@ -107,7 +109,8 @@107109 /** 0x03 adds each peer edge's relay URL so a newly introduced pair can agree108110 * on a route without depending on the introducing device. Coordinated wire109111 * change with peach-android. */110-export const DEVICE_MANIFEST_VERSION = 0x03 as const;112+export const DEVICE_MANIFEST_VERSION = 0x04 as const;113+export const MAX_VOUCH_DEPTH = 3;111114 /** Manifests older than this are silently rejected (v2 brief §4.3). */112115 export const DEVICE_MANIFEST_FRESHNESS_MS = 5 * 60_000;113116 @@ -133,6 +136,8 @@133136 /** Relay the issuer currently uses for this peer edge. */134137 relayUrl?: string;135138 pairedAt: number;139+ /** Number of vouching edges from a directly paired device. */140+ vouchDepth?: number;136141 }137142 138143 /**