/** * ipc/peering.ts — one hub talking to another, across machines. * * WHY PEERS AND NOT REMOTE CLIENTS. The obvious design is to let a session on * another machine dial this hub directly. It does not work: the hub finds * sessions by enumerating terminal panes on its own machine, and a pane on * another machine is not enumerable from here at all. So each machine runs its * own hub, which knows its own panes, and the hubs talk to each other. The * guest is then a first-class participant — its sessions appear in listings, * take messages and can be managed — rather than a special case threaded * through every call site. * * WHY THIS IS DANGEROUS AND WHAT IS DONE ABOUT IT. The local hub listens on a * unix socket, which is protected by file permissions and by not existing * anywhere else. This is a TCP port carrying commands that type into terminals * and drive screens. So: * * - it is OFF unless configured. There is no default port. * - it binds one named address. Never 0.0.0.0, which is refused outright * rather than warned about, because a warning nobody reads is not a control. * - every request must carry a shared secret, checked before dispatch. A * connection that can reach the port is not thereby trusted. * - the secret is generated, never chosen, and stored readable only by its * owner. * * The intended network is a private overlay — a Tailscale address or a host-only * link to a virtual machine. It is not intended to face anything else, and the * bind check is what keeps that from being a matter of memory. */ export interface PeerRecord { /** What a person calls it: "guest", "laptop". Used to address its sessions. */ name: string; host: string; port: number; /** Shared secret. Presented on every call in both directions. */ token: string; lastSeenAt?: number; lastError?: string; } export interface PeeringConfig { /** This hub's own listener. Absent means it accepts no peers. */ listen?: { host: string; port: number; token: string; }; /** Hubs this one reaches out to. */ peers: PeerRecord[]; } export declare function loadPeering(): PeeringConfig; export declare function savePeering(c: PeeringConfig): void; export declare function newToken(): string; /** * Compare secrets without leaking their contents through timing. * * Overkill for a home network and exactly the sort of thing that is never added * later. Lengths are compared first because timingSafeEqual throws on a * mismatch, and a thrown comparison is a failed comparison here. */ export declare function tokenMatches(given: unknown, expected: string): boolean; /** * Addresses this hub may bind to. * * A wildcard bind is refused rather than discouraged. The port accepts commands * that drive a machine's screen and keyboard; "we meant to change that later" * is how such a thing ends up facing a café network. If someone genuinely wants * it wide they can say so with an explicit address of their own choosing. */ export declare function rejectWildcard(host: string): string | null; /** * The single string that pairs two machines. * * Everything needed to connect, in one blob a person can copy once: where to * call, what secret to present, and what the other side calls itself. Pairing * that takes four fields typed into two machines is pairing that gets done * wrong at least once. */ export declare function makeInvite(name: string, host: string, port: number, token: string): string; export declare function readInvite(blob: string): { name: string; host: string; port: number; token: string; }; /** * Call a method on a peer hub. * * Same NDJSON request/response as the local socket, so a handler cannot tell * where a call came from and does not need to. The token rides in the envelope * rather than a header because there is no header — the protocol is one line of * JSON, and adding a framing layer for one field would be its own bug surface. */ export declare function peerCall(peer: PeerRecord, method: string, params?: Record, timeoutMs?: number): Promise<{ ok: boolean; result?: any; error?: string; }>; /** Address a session as `peer/session`, so a name cannot be ambiguous across machines. */ export declare function splitRemote(target: string): { peer: string; session: string; } | null; //# sourceMappingURL=peering.d.ts.map