Documentation
¶
Overview ¶
Package lanshare implements Share2Us's offline, account-free, direct peer-to-peer file transfer over a LAN / Tailscale / WireGuard / any reachable IP. It never touches the Share2Us cloud, relay, or TURN — this is the "actual guest mode": two machines, one TLS 1.3 connection, no login.
Security model (layered):
- Transport is always TLS 1.3 (confidentiality + integrity + forward secrecy).
- Password auth: a PAKE (schollz/pake) bound to the TLS exporter keying material — MITM-proof and immune to offline dictionary attack even on a weak password.
- QR / trusted-peer auth: the sender pins the receiver's self-signed cert SHA-256 fingerprint (delivered out-of-band via the QR / saved config).
- --allow-ip: source-IP allowlist (auth by network identity); TLS still provides confidentiality. Active on-path MITM on an untrusted L2 is out of scope for this mode (callers are warned).
Index ¶
- Constants
- func Advertise(instance string, info ListenInfo) (io.Closer, error)
- func BuildPairingString(host string, info ListenInfo) string
- func GeneratePassphrase(n int) (string, error)
- func IsPairingString(s string) bool
- func Send(ctx context.Context, name string, size int64, isDir bool, body io.Reader, ...) (string, error)
- type ListenInfo
- type PairingInfo
- type ReceiveOptions
- type ReceiveResult
- type SendOptions
Constants ¶
const ( ModePassword = "password" ModeAllowIP = "allow-ip" ModeOpen = "open" )
Auth modes reported in ListenInfo.Mode.
const DefaultPassphraseWords = 10
DefaultPassphraseWords is the number of diceware words in an auto-generated receive passphrase. Ten EFF-large-list words is ~129 bits of entropy, which makes the PAKE's password path immune to any offline guessing.
const (
// DefaultPort is the first port a receiver tries when none is pinned.
DefaultPort = 4300
)
const PairingScheme = "s2u"
PairingScheme is the URL scheme for a pairing string. A pairing string bundles everything a sender needs for a one-scan/one-paste transfer: the address, the receiver's cert fingerprint (pinned to defeat MITM), and, in password mode, the passphrase (the string is shown on the receiver's own screen, so whoever can read it to scan/paste it is already trusted).
Variables ¶
This section is empty.
Functions ¶
func Advertise ¶
func Advertise(instance string, info ListenInfo) (io.Closer, error)
Advertise announces a live receiver on the local network via mDNS so a sender can find it by name (`--dest <name>`). The TXT record carries the cert fingerprint and mode, but never the passphrase — password-mode receivers are still discovered, but the sender must supply the password out-of-band.
func BuildPairingString ¶
func BuildPairingString(host string, info ListenInfo) string
BuildPairingString encodes a pairing string for a live receiver. host should be the address a sender can reach (e.g. the primary LAN / Tailscale IP).
func GeneratePassphrase ¶
GeneratePassphrase returns a space-free, hyphen-joined diceware passphrase of n words drawn from the EFF large word list using crypto/rand. It is used when a receiver is opened without an explicit -p/--password and without -np.
func IsPairingString ¶
IsPairingString reports whether s looks like a pairing string.
func Send ¶
func Send(ctx context.Context, name string, size int64, isDir bool, body io.Reader, opts SendOptions) (string, error)
Send streams name/size/body to a receiver at opts.Dest. IsDir marks that body is a zip of a directory (the receiver may extract it). It returns the peer's reported SHA-256 on success.
Types ¶
type ListenInfo ¶
type ListenInfo struct {
BindAddr string
Port int
Fingerprint string // self-signed cert SHA-256 (for QR / pairing)
Passphrase string // effective password in password mode; "" otherwise
Mode string // ModePassword | ModeAllowIP | ModeOpen
}
ListenInfo describes a live receiver.
type PairingInfo ¶
PairingInfo is the decoded content of a pairing string.
func Discover ¶
Discover browses the local network for a receiver whose instance name matches name (case-insensitive) and returns its address + fingerprint. Password is never carried over mDNS, so PairingInfo.Password is always empty here.
func ParsePairingString ¶
func ParsePairingString(s string) (PairingInfo, error)
ParsePairingString decodes a pairing string produced by BuildPairingString.
type ReceiveOptions ¶
type ReceiveOptions struct {
// Bind is the interface address to listen on ("" = all interfaces).
Bind string
// Port pins the listen port. 0 = auto-scan DefaultPort..portRangeEnd. A
// pinned port that is unavailable is a hard error (no fallback).
Port int
// Password sets an explicit receive password (PAKE). Empty + !NoPassword +
// no AllowIPs => a passphrase is auto-generated.
Password string
// NoPassword opens the receiver with no password (caller should warn).
NoPassword bool
// AllowIPs restricts accepted source IPs. With AllowIPs and no password, the
// mode is allow-ip (network-identity auth).
AllowIPs []string
// TrustedIPs are source IPs whose inbound transfers are auto-accepted even
// when a password is set for everyone else (trust-by-IP; caller warns).
TrustedIPs []string
// DestDir is where files land (default ~/s2u, created if missing).
DestDir string
// Overwrite permits replacing an existing destination file.
Overwrite bool
// HandshakeTimeout bounds per-connection setup (default 30s).
HandshakeTimeout time.Duration
// OnListen fires once the listener is up, before accepting.
OnListen func(ListenInfo)
// OnProgress fires as bytes arrive.
OnProgress func(received, total int64)
}
ReceiveOptions configures a single inbound transfer.
type ReceiveResult ¶
ReceiveResult reports a completed transfer.
func Receive ¶
func Receive(ctx context.Context, opts ReceiveOptions) (ReceiveResult, error)
Receive opens a listener, accepts connections until one completes a full authenticated transfer, writes the file atomically into DestDir, and returns. Connections that fail allow-ip, TLS, auth, or local checks are closed and the listener keeps waiting (so junk/probe connections cannot abort a receive).
type SendOptions ¶
type SendOptions struct {
// Dest is host or host:port. When no port is given, DefaultPort is used.
Dest string
// Password, when non-empty, drives the PAKE. Leave empty for an allow-ip /
// open receiver.
Password string
// PinFingerprint pins the receiver's self-signed cert SHA-256 fingerprint
// (from a QR / pairing string / trusted-device entry). Empty = unpinned.
PinFingerprint string
// DialTimeout / HandshakeTimeout bound connection setup.
DialTimeout time.Duration
HandshakeTimeout time.Duration
// OnProgress, if set, is called as bytes are sent.
OnProgress func(sent, total int64)
}
SendOptions configures a direct LAN/overlay send. The caller resolves the source (zipping a folder to a temp file first) and supplies its name + size.