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 ¶
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 ¶ added in v0.9.0
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
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.
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.
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.
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.