common

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MPL-2.0 Imports: 34 Imported by: 0

Documentation

Overview

SPDX-License-Identifier: MPL-2.0 Copyright (c) 2025 KeibiSoft S.R.L. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

SPDX-License-Identifier: MPL-2.0 Copyright (c) 2025 KeibiSoft S.R.L. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

Index

Constants

View Source
const Timeout = 10*60 - 5

Variables

View Source
var (
	Version    = "0.0.0"
	CommitHash = "dev" // default fallback
)
View Source
var (
	ErrNilPointer                    = errors.New("nil pointer")
	ErrEmptyFingerprint              = errors.New("fingerprint is empty")
	ErrInvalidLength                 = errors.New("invalid length")
	ErrRelayAtMaximumCapacity        = errors.New("relay at maximum capacity")
	ErrRateLimitHit                  = errors.New("relay rate limit hit, retry in 5 minutes")
	ErrMissingFingerprint            = errors.New("missing fingerprint header")
	ErrInvalidPayload                = errors.New("invalid registration payload")
	ErrMissingKeys                   = errors.New("missing public keys")
	ErrInvalidFingerprint            = errors.New("invalid fingerprint format")
	ErrServerError                   = errors.New("server error")
	ErrTemporaryRetry                = errors.New("temporary network issue")
	ErrTimeoutReached                = errors.New("timeout reached")
	ErrFingerprintMismatch           = errors.New("fingerprint mismatch")
	ErrRelayAtFullCapacityRetryLater = errors.New("relay at full capacity, retry later")
	ErrNotFound                      = errors.New("not found")
	ErrInvalidResponse               = errors.New("invalid response")
	ErrInvalidIP                     = errors.New("invalid IP")
	ErrSessionNotEstablished         = errors.New("session not established")
	ErrFilesystemAlreadyMounted      = errors.New("filesystem already mounted")
	ErrNilFilesystem                 = errors.New("filesystem not mounted")
	ErrAlreadyRunning                = errors.New("already running")
	ErrInvalidSession                = errors.New("invalid session")
	ErrServerAtCapacity              = errors.New("relay server at capacity, please try again in 5 minutes")
	ErrIdenticalFingerprints         = errors.New("own and peer fingerprints are identical")
)

Functions

func GetGlobalIPv6

func GetGlobalIPv6() (string, error)

GetGlobalIPv6 returns a stable (non-temporary) global IPv6 address. On macOS/Linux, privacy extensions (RFC 4941) generate temporary addresses that rotate periodically. Connections bound to a temporary address break when the OS deprecates it. This function prefers stable addresses by collecting all candidates and picking the best one.

func GetJSONWithURL

func GetJSONWithURL(client *http.Client, endpoint *url.URL, headers map[string]string, mapError ErrorMapperFunc) (*http.Response, error)

func GetLinkLocalAddress

func GetLinkLocalAddress(port int) (string, error)

GetLinkLocalAddress finds a link-local IPv6 address on this machine and returns it formatted as "ip%zone:port" for direct LAN peer connections. Falls back to loopback (::1) when no link-local interface is available.

func GetLocalAddrs

func GetLocalAddrs() []string

GetLocalAddrs returns all private/link-local IP addresses for LAN discovery. These are included in the relay registration so peers on the same network can connect directly without going through the bridge relay.

func GetLocalIPv6

func GetLocalIPv6() (string, error)

func NewSingleConnListener

func NewSingleConnListener(conn net.Conn) net.Listener

func ParsePeerDirectAddress

func ParsePeerDirectAddress(addr string) (ip string, zone string, port int, err error)

ParsePeerDirectAddress parses a direct LAN peer address in the format "ip%zone:port" (link-local) or "ip:port" (loopback). Returns the IP, zone identifier, port number, and any error.

func PostJSONWithURL

func PostJSONWithURL(client *http.Client, endpoint *url.URL, headers map[string]string, payload interface{}, mapError ErrorMapperFunc) (*http.Response, error)

func PrintBanner

func PrintBanner()

func RegisterErrorMapper

func RegisterErrorMapper(statusCode int, err error) error

func SanitizeLogContent

func SanitizeLogContent(raw string) string

SanitizeLogContent sanitizes log text in memory.

func SanitizeLogs

func SanitizeLogs(logPath string) (string, error)

SanitizeLogs reads a log file and returns sanitized content. Redacts file names (keeps extensions), fingerprints, and IP addresses. Keeps timestamps, log levels, method names, error types, sizes, and connection events.

func SanitizeLogsToFile

func SanitizeLogsToFile(logPath, destPath string) error

SanitizeLogsToFile reads a log, sanitizes it, and writes to destPath.

func ValidateFingerprint

func ValidateFingerprint(fp string) error

Types

type ConnectionHint

type ConnectionHint struct {
	IP    string `json:"ip"`             // public IP address (either v4 or v6)
	Port  int    `json:"port"`           // where peer is listening
	IPv6  bool   `json:"ipv6"`           // does this prefer IPv6?
	Proto string `json:"proto"`          // e.g., "tcp"
	Note  string `json:"note,omitempty"` // optional: NAT behavior, etc.
}

type EnableOpts added in v0.2.0

type EnableOpts struct {
	PassphraseProtect  bool
	PassphraseProvider func() (string, error)
}

EnableOpts controls how persistent identity is loaded:

  • PassphraseProtect: opt into Tier 2 (passphrase-derived key). Requires PassphraseProvider to be non-nil.
  • PassphraseProvider: called once when PassphraseProtect=true to obtain the user's passphrase. Typical sources: TTY prompt (CLI), stdin (rustbridge / FFI), test stub.

type EncryptedRegistration

type EncryptedRegistration struct {
	Blob   string `json:"blob"`             // base64-encoded ChaCha20-Poly1305 ciphertext
	Bridge string `json:"bridge,omitempty"` // relay-suggested bridge address (e.g., "fra1.bridge.keibisoft.com:26600")
	Tier   string `json:"tier,omitempty"`   // bandwidth tier: "free", "priority" (relay metadata, not encrypted)
}

EncryptedRegistration is the relay-visible payload (opaque blob). The relay cannot read the contents - only the peers with the shared room password can decrypt it.

type ErrorMapperFunc

type ErrorMapperFunc func(statusCode int, err error) error

Map server status errors to semantic errors.

type ImplFileStreamProvider

type ImplFileStreamProvider struct {
	// contains filtered or unexported fields
}

func (*ImplFileStreamProvider) OpenRemoteFile

func (sp *ImplFileStreamProvider) OpenRemoteFile(ctx context.Context, inode uint64, path string) (types.RemoteFileStream, error)

func (*ImplFileStreamProvider) StreamFile

func (sp *ImplFileStreamProvider) StreamFile(ctx context.Context, path string, startOffset uint64) (types.StreamFileReceiver, error)

StreamFile starts a push-based download using the server-streaming StreamFile RPC.

type ImplRemoteFileStream

type ImplRemoteFileStream struct {
	// contains filtered or unexported fields
}

func (*ImplRemoteFileStream) Close

func (rfs *ImplRemoteFileStream) Close() error

func (*ImplRemoteFileStream) ReadAt

func (rfs *ImplRemoteFileStream) ReadAt(ctx context.Context, offset int64, size int64) ([]byte, error)

type KeibiDrop

type KeibiDrop struct {
	RelayEndoint *url.URL

	Identity    *identity.DeviceIdentity
	AddressBook *identity.AddressBook
	Incognito   bool

	IsFUSE         bool
	IsLocalMode    bool
	BridgeAddr     string // TCP bridge relay address for firewall traversal
	StrictMode     bool   // Disable data relay fallback (direct connections only)
	ConnectionMode string // "lan", "direct", "bridge" - set after successful connection
	OpInProgress   atomic.Int32

	PeerIPv6IP     string
	PeerLocalAddrs []string // LAN IPs from relay registration (for same-network direct connect)

	LocalIPv6IP string

	// Filesystem.
	FS       *filesystem.FS
	KDSvc    *service.KeibidropServiceImpl
	KDClient bindings.KeibiServiceClient

	// Non-FUSE fallback.
	SyncTracker *synctracker.SyncTracker

	// Paths for virtual mount point and for save folder.
	ToMount string
	ToSave  string

	// Collab sync options.
	PrefetchOnOpen bool
	PushOnWrite    bool

	Cancel context.CancelFunc // exported so FFI layer can call it for app exit

	// Event callback (wired by FFI layer to push events to the UI).
	OnEvent func(string)

	// Connection resilience.
	HealthMonitor    *session.HealthMonitor
	ReconnectManager *session.ReconnectManager
	RelayKeepalive   *RelayKeepalive
	// contains filtered or unexported fields
}

func NewKeibiDrop

func NewKeibiDrop(ctx context.Context, logger *slog.Logger, isFuse bool, relayURL *url.URL, inboundPort int, defaultOutboundPort int, toMount string, toSave string, prefetchOnOpen bool, pushOnWrite bool) (*KeibiDrop, error)

Factory-style constructor

func NewKeibiDropWithIP

func NewKeibiDropWithIP(ctx context.Context, logger *slog.Logger, isFuse bool, relayURL *url.URL, inboundPort int, defaultOutboundPort int, toMount string, toSave string, prefetchOnOpen bool, pushOnWrite bool, ipv6Address string) (*KeibiDrop, error)

NewKeibiDropWithIP is identical to NewKeibiDrop but accepts an explicit IPv6 address instead of probing the network. This enables testing on machines without a global IPv6 address.

func (*KeibiDrop) AddFile

func (kd *KeibiDrop) AddFile(path string) error

Add a file to be tracked.

func (*KeibiDrop) AddFileAs

func (kd *KeibiDrop) AddFileAs(localPath string, remoteName string) error

AddFileAs adds a file with a custom remote name (preserving folder structure). Automatically sends ADD_DIR for any parent directories the peer may not have.

func (*KeibiDrop) AddPeerFingerprint

func (kd *KeibiDrop) AddPeerFingerprint(fp string) error

func (*KeibiDrop) CancelDownload

func (kd *KeibiDrop) CancelDownload(remoteName string) error

CancelDownload cancels an active download. The partial file and bitmap are preserved on disk so the next PullFile call resumes automatically.

func (*KeibiDrop) CheckContactPresence added in v0.2.0

func (kd *KeibiDrop) CheckContactPresence(fingerprint string) bool

CheckContactPresence returns true if the contact was seen online recently.

func (*KeibiDrop) Connect

func (kd *KeibiDrop) Connect() error

Connect determines the creator/joiner role automatically using deterministic fingerprint comparison and calls CreateRoom or JoinRoom. Lower fingerprint = creator (registers to relay, accepts inbound). Higher fingerprint = joiner (fetches from relay, dials out).

func (*KeibiDrop) ConnectToContact added in v0.2.0

func (kd *KeibiDrop) ConnectToContact(fingerprint string) error

ConnectToContact looks up a contact by fingerprint, registers it, and connects.

func (*KeibiDrop) ConnectionStatus

func (kd *KeibiDrop) ConnectionStatus() string

ConnectionStatus returns the current connection health status.

func (*KeibiDrop) CreateRoom

func (kd *KeibiDrop) CreateRoom() error

func (*KeibiDrop) DowngradeListenerIPv6Only

func (kd *KeibiDrop) DowngradeListenerIPv6Only() error

DowngradeListenerIPv6Only replaces the dual-stack listener with an IPv6-only listener. Used when leaving local mode.

func (*KeibiDrop) EnablePersistentIdentity added in v0.2.0

func (kd *KeibiDrop) EnablePersistentIdentity(configDir string, opts EnableOpts) error

EnablePersistentIdentity replaces ephemeral keys with a stable device identity. Must be called before CreateRoom/JoinRoom. Loads or creates identity from configDir, rebuilds the session with stable keys, and loads the address book.

func (*KeibiDrop) EnablePersistentIdentityDefault added in v0.2.0

func (kd *KeibiDrop) EnablePersistentIdentityDefault(configDir string) error

EnablePersistentIdentityDefault is a convenience wrapper that uses zero-value EnableOpts (keychain or file tier, no passphrase).

func (*KeibiDrop) ExportFingerprint

func (kd *KeibiDrop) ExportFingerprint() (string, error)

func (*KeibiDrop) GetDownloadProgress

func (kd *KeibiDrop) GetDownloadProgress(remoteName string) float64

GetDownloadProgress returns the download progress for a file as a fraction [0.0, 1.0]. Returns -1 if the file has no active or resumable download.

func (*KeibiDrop) GetPeerFingerprint

func (kd *KeibiDrop) GetPeerFingerprint() (string, error)

func (*KeibiDrop) InboundPort

func (kd *KeibiDrop) InboundPort() int

InboundPort returns the port this instance listens on for incoming connections.

func (*KeibiDrop) InitConnectionResilience

func (kd *KeibiDrop) InitConnectionResilience() error

InitConnectionResilience sets up health monitoring, reconnection, and relay keepalive. Call this after the session is connected and gRPC client is ready.

func (*KeibiDrop) IsPeerPersistent added in v0.2.0

func (kd *KeibiDrop) IsPeerPersistent() bool

IsPeerPersistent returns whether the currently connected peer has a stable identity.

func (*KeibiDrop) IsRunning

func (kd *KeibiDrop) IsRunning() bool

IsRunning returns whether the KeibiDrop instance is in a connected session.

func (*KeibiDrop) JoinRoom

func (kd *KeibiDrop) JoinRoom() error

func (*KeibiDrop) ListFiles

func (kd *KeibiDrop) ListFiles() (remote []string, local []string)

func (*KeibiDrop) MountFilesystem

func (kd *KeibiDrop) MountFilesystem(toMount string, toSave string, isSecond bool) error

This is blocking.

func (*KeibiDrop) NotifyDisconnect

func (kd *KeibiDrop) NotifyDisconnect()

NotifyDisconnect sends a best-effort DISCONNECT notification to the peer so they can clean up immediately instead of waiting for health monitor timeout.

func (*KeibiDrop) PullFile

func (kd *KeibiDrop) PullFile(remoteName, localPath string) error

func (*KeibiDrop) PullFileWithParams

func (kd *KeibiDrop) PullFileWithParams(remoteName, localPath string, blockSize, nWorkers int) error

PullFileWithParams downloads remoteName to localPath using the specified blockSize (bytes per gRPC chunk) and nWorkers (parallel streams). Intended for benchmarking; production code uses PullFile with defaults.

func (*KeibiDrop) ReconnectionAttempts

func (kd *KeibiDrop) ReconnectionAttempts() int

ReconnectionAttempts returns the number of reconnection attempts.

func (*KeibiDrop) ReconnectionState

func (kd *KeibiDrop) ReconnectionState() string

ReconnectionState returns the current reconnection state.

func (*KeibiDrop) Run

func (kd *KeibiDrop) Run()

Run as a go-routine.

func (*KeibiDrop) SaveCurrentPeerAsContact added in v0.2.0

func (kd *KeibiDrop) SaveCurrentPeerAsContact(name string) error

SaveCurrentPeerAsContact saves the currently connected peer as a named contact.

func (*KeibiDrop) SetPeerDirectAddress

func (kd *KeibiDrop) SetPeerDirectAddress(addr string) error

SetPeerDirectAddress parses a direct LAN peer address (e.g. "fe80::1%eth0:26431"), stores the peer IP and port, and sets TOFU mode for the handshake.

func (*KeibiDrop) Shutdown

func (kd *KeibiDrop) Shutdown()

Shutdown permanently stops the Run() goroutine. Use this for app exit. For temporary disconnects (peer left), use Stop() instead. Safe to call multiple times from any goroutine.

func (*KeibiDrop) Start

func (kd *KeibiDrop) Start()

Running process for KeibiDrop.

func (*KeibiDrop) StartPresenceHeartbeat added in v0.2.0

func (kd *KeibiDrop) StartPresenceHeartbeat(ctx context.Context)

StartPresenceHeartbeat sends periodic presence heartbeats for all contacts. Runs until ctx is cancelled. Should be called after EnablePersistentIdentity.

func (*KeibiDrop) Stop

func (kd *KeibiDrop) Stop()

Stop cleanly disconnects the current session. Run() continues after cleanup, ready for the next CreateRoom/JoinRoom. Thread-safe.

func (*KeibiDrop) StopConnectionResilience

func (kd *KeibiDrop) StopConnectionResilience()

StopConnectionResilience stops all resilience components.

func (*KeibiDrop) ToggleIncognito added in v0.2.0

func (kd *KeibiDrop) ToggleIncognito(incognito bool, configDir string) (string, error)

ToggleIncognito switches between persistent and ephemeral identity. When enabling incognito: generates fresh ephemeral keys. When disabling: restores persistent identity keys. Returns the new fingerprint.

func (*KeibiDrop) UnmountFilesystem

func (kd *KeibiDrop) UnmountFilesystem() error

func (*KeibiDrop) UpgradeListenerDualStack

func (kd *KeibiDrop) UpgradeListenerDualStack() error

UpgradeListenerDualStack replaces the IPv6-only listener with a dual-stack listener that accepts both IPv4 and IPv6. Used when entering local mode (LAN discovery needs IPv4 connectivity).

type PeerRegistration

type PeerRegistration struct {
	Fingerprint string            `json:"fingerprint"`
	PublicKeys  map[string]string `json:"public_keys"` // base64 encoded
	Listen      *ConnectionHint   `json:"listen"`
	Reverse     *ConnectionHint   `json:"reverse,omitempty"`
	LocalAddrs  []string          `json:"local_addrs,omitempty"` // LAN IPs (192.168.x.x, fe80::x) for same-network detection
	Timestamp   int64             `json:"timestamp"`
}

type RelayKeepalive

type RelayKeepalive struct {

	// Configuration
	Interval time.Duration // Refresh interval (default 8 min, relay TTL is 10 min)
	// contains filtered or unexported fields
}

RelayKeepalive maintains relay registration by periodically refreshing before the TTL expires. This ensures peers can always find each other.

func NewRelayKeepalive

func NewRelayKeepalive(kd *KeibiDrop, logger *slog.Logger) *RelayKeepalive

NewRelayKeepalive creates a new relay keepalive manager.

func (*RelayKeepalive) CheckIPChange

func (rk *RelayKeepalive) CheckIPChange() error

CheckIPChange detects if the local IP has changed and refreshes if needed. Call this periodically or on network state change.

func (*RelayKeepalive) FailureCount

func (rk *RelayKeepalive) FailureCount() int

FailureCount returns the number of consecutive refresh failures.

func (*RelayKeepalive) ForceRefresh

func (rk *RelayKeepalive) ForceRefresh() error

ForceRefresh immediately refreshes the relay registration. Call this on IP change or reconnection.

func (*RelayKeepalive) LastRefresh

func (rk *RelayKeepalive) LastRefresh() time.Time

LastRefresh returns the timestamp of the last successful refresh.

func (*RelayKeepalive) Pause

func (rk *RelayKeepalive) Pause()

Pause temporarily disables refresh (e.g., when disconnected).

func (*RelayKeepalive) Resume

func (rk *RelayKeepalive) Resume()

Resume re-enables refresh.

func (*RelayKeepalive) Start

func (rk *RelayKeepalive) Start()

Start begins the background refresh loop.

func (*RelayKeepalive) Stop

func (rk *RelayKeepalive) Stop()

Stop halts the background refresh loop.

type TaskSignal

type TaskSignal int
const (
	Start TaskSignal = iota
	Stop
)

Jump to

Keyboard shortcuts

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