lansync

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 24, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package lansync implements cct's experimental device-to-device session sync over a local network. It is the project's only feature that sends session data off the machine, so it is strictly opt-in, peer-to-peer (no server/relay/cloud), refuses non-private addresses by default, and authenticates the peer with a high-entropy pairing code before any data moves.

Security model (stdlib only, no PAKE/mDNS dependency):

  • The channel is TLS with per-process self-signed certificates (mutual auth). Trust is NOT delegated to a CA.
  • The pairing code is a freshly generated ~96-bit secret shown by the serving side. Both sides derive a key from it and exchange an HMAC confirmation bound to BOTH TLS certificate fingerprints (channel binding). A man-in-the- middle terminates TLS separately with each side, so the fingerprints it presents differ from the real ones; without the code it cannot forge the confirmation, and the code's entropy makes offline guessing infeasible.

The actual session transfer reuses the existing, tested bundle export/import (+ --merge) path verbatim, so all checksum/manifest/conflict/mtime guarantees carry over unchanged.

Index

Constants

View Source
const ExperimentalNotice = "EXPERIMENTAL: cct sync sends your sessions over the local network to a paired device.\n" +
	"It talks only to a peer you confirm with a one-time code, never to a server or the internet,\n" +
	"and refuses non-private addresses. Re-run with --i-understand to proceed."

ExperimentalNotice is shown before every run because sync sends data off-machine.

Variables

This section is empty.

Functions

func Advertise(ctx context.Context, b Beacon) error

Advertise multicasts the given beacon every beaconInterval until ctx is done. It is best-effort: a failure to open the socket returns an error, but transient write errors are ignored so a flaky interface does not kill a daemon.

func ApplyDelta added in v0.9.0

func ApplyDelta(current []byte, plan DeltaPlan) ([]byte, error)

ApplyDelta reconstructs the sender's file on the receiver. For an append it requires current to be exactly the known prefix; in every case it verifies the result matches the sender's advertised SHA before returning it, so a bad delta is rejected rather than written.

func Daemon added in v0.9.0

func Daemon(ctx context.Context, home codexhome.Home, opts Options, dopts DaemonOptions) error

Daemon runs the ambient sync loop until ctx is cancelled (or, with Once, for a single sweep). It requires --i-understand and at least one remembered peer.

Types

type Beacon added in v0.9.0

type Beacon struct {
	Magic       string `json:"cct"`         // protocol marker, always beaconMagic
	Hostname    string `json:"hostname"`    // human label
	Tool        string `json:"tool"`        // codex | claude
	Port        int    `json:"port"`        // the sync TCP port to dial
	Fingerprint string `json:"fingerprint"` // sender's cert fingerprint (hex), for trust recognition
	// Addr is filled in by the discoverer from the datagram source; it is not sent
	// on the wire (the sender does not know which interface a peer sees it on).
	Addr string `json:"-"`
}

Beacon is the advertised, non-secret description of a discoverable peer.

func Discover added in v0.9.0

func Discover(ctx context.Context, timeout time.Duration, tool string) ([]Beacon, error)

Discover listens for beacons for up to timeout and returns the distinct peers seen (optionally filtered to one tool). It never blocks longer than timeout.

type DaemonOptions added in v0.9.0

type DaemonOptions struct {
	// Interval is how often the sessions directory is polled for changes.
	Interval time.Duration
	// DiscoverWindow is how long each discovery sweep listens for peers.
	DiscoverWindow time.Duration
	// Once runs a single discover-and-sync sweep, then returns (no listener). It is
	// used by `--once` and keeps the daemon testable/scriptable.
	Once bool
}

DaemonOptions configures a daemon run, on top of the shared sync Options.

type DeltaPlan added in v0.9.0

type DeltaPlan struct {
	// Append is true when the receiver holds an exact prefix and only the trailing
	// Suffix bytes need to be sent and appended. When false the whole file must be
	// sent (the receiver lacks it, or its copy diverged and is not a clean prefix).
	Append bool
	Suffix []byte // bytes to append (Append==true)
	Full   []byte // whole file to send (Append==false)
	// SHA256 is the sender's whole-file hash, which the receiver verifies after
	// applying, so a corrupt or mis-targeted transfer can never be committed.
	SHA256 string
}

DeltaPlan describes how to bring a receiver's copy of one session up to date.

func PlanDelta added in v0.9.0

func PlanDelta(senderFile []byte, receiverSize int64, receiverSHA string) DeltaPlan

PlanDelta computes how to update a receiver, given the sender's current file bytes and the receiver's advertised (size, sha256). receiverSize<0 (or an empty receiverSHA) means the receiver does not have the session at all.

type Options

type Options struct {
	Tool        agent.Kind      // codex or claude
	ClaudeHome  claudehome.Home // used to scan when Tool == claude
	ProjectPath string          // absolute; "" means all in-scope sessions
	Port        int             // serve: listen port (0 = OS-assigned)
	Code        string          // connect: the pairing code shown by the peer
	AllowPublic bool            // override the private-address guard
	PullOnly    bool            // do not send my sessions
	PushOnly    bool            // do not apply received sessions
	DryRun      bool            // exchange manifests and preview only; write nothing
	Confirmed   bool            // the experimental --i-understand gate
	Out         io.Writer       // progress/UX output
	// MapCWD / MapCWDHere / HereDir remap a received session's recorded cwd as it
	// is applied, so a peer's project that lives at a different path here still
	// lands under the right local project (and, for Claude, the right sidebar
	// group). Same semantics as on import.
	MapCWD     []bundle.CWDMapping
	MapCWDHere bool
	HereDir    string
	// Remember stores the peer's fingerprint after a successful code pairing
	// (trust-on-first-use), so future syncs between remembered devices skip the
	// code. ConfigDir overrides the location of the identity/peers store (default:
	// the OS config dir); used in tests.
	Remember  bool
	ConfigDir string
	// Redact replaces likely secrets in the sessions this device sends with
	// placeholders before they leave the machine. AllowSecrets disables the
	// pre-egress secret gate (which otherwise refuses to send a session containing
	// a likely secret). Redact and the gate apply to outbound data only.
	Redact       bool
	AllowSecrets bool
}

Options configures one LAN sync run.

type Result

type Result struct {
	PeerHost    string
	Sent        int
	Received    bundle.ImportResult
	DryRun      bool
	PreviewSend int
	PreviewRecv int
}

Result summarizes a sync from the local side's perspective.

func Connect

func Connect(home codexhome.Home, opts Options, hostport string) (Result, error)

Connect dials a peer and syncs using the code the peer displayed.

func Serve

func Serve(home codexhome.Home, opts Options) (Result, error)

Serve waits for one peer to connect, authenticates it with a freshly generated pairing code, and syncs. home is the import target (for Claude, a codexhome.Home whose Root is the Claude home root).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL