mesh-peer-role.ts

1.8 KB · raw

1import type { PairedDevice } from "./sync-types";23export const MESH_WAITER_RETRY_DELAY_MS = 2_000;4export const MESH_WAITER_MAX_RETRY_DELAY_MS = 30_000;56export function isRouteCapableMeshPeer(device: PairedDevice): boolean {7  // PB-26-006: fail closed on an unknown/absent trustSource — sibling trust8  // gates reject it, so routing must not treat it as direct/vouched.9  const trusted =10    device.trustSource === "direct" || device.trustSource === "vouched";11  return (12    trusted &&13    (device.deviceType === "extension" ||14      device.deviceType === "android" ||15      device.deviceType === "ios") &&16    typeof device.longTermPublicKeyHex === "string" &&17    /^[0-9a-f]{64}$/.test(device.longTermPublicKeyHex) &&18    typeof device.rendezvousSecretHex === "string" &&19    /^[0-9a-f]{64}$/.test(device.rendezvousSecretHex)20  );21}2223/** Lower public key dials; higher public key waits. */24export function weDialMeshPeer(25  ourLongTermPublicKeyHex: string,26  peerLongTermPublicKeyHex: string,27): boolean {28  if (29    !/^[0-9a-f]{64}$/.test(ourLongTermPublicKeyHex) ||30    !/^[0-9a-f]{64}$/.test(peerLongTermPublicKeyHex) ||31    ourLongTermPublicKeyHex === peerLongTermPublicKeyHex32  ) {33    return false;34  }35  return ourLongTermPublicKeyHex < peerLongTermPublicKeyHex;36}3738export function selectDialTargets(39  devices: PairedDevice[],40  ourLongTermPublicKeyHex: string,41): PairedDevice[] {42  return devices.filter(43    (device) =>44      isRouteCapableMeshPeer(device) &&45      weDialMeshPeer(46        ourLongTermPublicKeyHex,47        device.longTermPublicKeyHex!,48      ),49  );50}5152export function nextMeshWaiterRetryDelay(53  current: number,54  succeeded: boolean,55): number {56  return succeeded57    ? MESH_WAITER_RETRY_DELAY_MS58    : Math.min(current * 2, MESH_WAITER_MAX_RETRY_DELAY_MS);59}