server

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 59 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuditHeadShippingOptions added in v0.2.0

type AuditHeadShippingOptions struct {
	URL         string
	BearerToken string
	Interval    time.Duration
	HTTPClient  *http.Client
}

AuditHeadShippingOptions configures automated off-box custody for the verified audit WAL head. Empty URL disables shipping.

type BuildInfo added in v0.2.0

type BuildInfo struct {
	ServerVersion         string `json:"server_version"`
	ServerCommit          string `json:"server_commit"`
	ServerDate            string `json:"server_date"`
	DashboardRef          string `json:"dashboard_ref,omitempty"`
	DashboardBuilt        string `json:"dashboard_built,omitempty"`
	TaskExecutionDisabled bool   `json:"task_execution_disabled,omitempty"`
}

type Line added in v0.2.0

type Line struct {
	ID               string            `json:"id"`           // == LineHashID (stable handle)
	LineHashID       string            `json:"line_hash_id"` // stable across re-probes; see lineHash / stableLineHandle
	LineID           string            `json:"line_id,omitempty"`
	NodeID           string            `json:"node_id"`
	NodeIdentityUUID string            `json:"node_identity_uuid,omitempty"`
	Core             string            `json:"core"`    // sing-box | xray | mihomo
	Source           string            `json:"source"`  // managed | discovered | imported
	Managed          bool              `json:"managed"` // under Lattice config management
	Name             string            `json:"name"`
	Tag              string            `json:"tag,omitempty"`
	Type             string            `json:"type,omitempty"` // protocol
	ListenHost       string            `json:"listen_host,omitempty"`
	ListenPort       int               `json:"listen_port,omitempty"`
	PublicHost       string            `json:"public_host,omitempty"`
	Domain           string            `json:"domain,omitempty"`
	OutboundRef      string            `json:"outbound_ref,omitempty"`    // direct | <host/tag> | "" unknown
	OutboundServer   string            `json:"outbound_server,omitempty"` // downstream server host the outbound routes to
	OutboundPort     int               `json:"outbound_port,omitempty"`   // downstream server port the outbound routes to
	JumpEdges        []string          `json:"jump_edges,omitempty"`      // line_hash_ids this line relays to
	UserCount        int               `json:"user_count"`
	UserKnown        bool              `json:"user_known"`       // false ⇒ discovered line, count not yet inspected
	Status           string            `json:"status,omitempty"` // ok | pending | error | stale
	LastError        string            `json:"last_error,omitempty"`
	Metadata         map[string]string `json:"metadata,omitempty"` // sing-box `_lattice` block (future enrich)
}

Line is the unified, node-grouped view of a proxy "line" — an inbound/endpoint regardless of origin: a Lattice-managed inbound rendered onto a node, or a proxy discovered on-box via `sb --json list`. It replaces the split between the old managed Inbounds view and the Discovered view (design-12). It is a DERIVED, read-model type computed on demand from the proxy store + live discovery inventory; it is not persisted and is never sent to the agent (so it lives in the server package, not the shared SDK). Secret-free: it carries only connection-shape metadata, never private keys or passwords.

type LineBinding added in v0.2.0

type LineBinding struct {
	LineHashID   string `json:"line_hash_id"`
	Enabled      bool   `json:"enabled"`
	FlowOverride string `json:"flow_override,omitempty"`
}

LineBinding attaches a user to a specific Line (by its stable line_hash_id).

type LineGroup added in v0.2.0

type LineGroup struct {
	NodeID   string `json:"node_id"`
	NodeName string `json:"node_name,omitempty"`
	Lines    []Line `json:"lines"`
}

LineGroup is the set of lines on one node — the unit the dashboard renders.

type NodeProfileRuntime added in v0.2.0

type NodeProfileRuntime struct {
	NodeID          string                 `json:"node_id"`
	NodeName        string                 `json:"node_name,omitempty"`
	Managed         bool                   `json:"managed"` // a Lattice ProxyNodeProfile exists
	Core            string                 `json:"core,omitempty"`
	CoreVersion     string                 `json:"core_version,omitempty"`
	ConfigPath      string                 `json:"config_path,omitempty"`
	StatsAPI        string                 `json:"stats_api,omitempty"`
	Applied         bool                   `json:"applied"`
	LastApplyAt     string                 `json:"last_apply_at,omitempty"`
	LastError       string                 `json:"last_error,omitempty"`
	InboundCount    int                    `json:"inbound_count"`
	DiscoveredCount int                    `json:"discovered_count"`
	DiscoveryStatus string                 `json:"discovery_status,omitempty"`
	DiscoveryError  string                 `json:"discovery_error,omitempty"`
	DiscoveredAt    string                 `json:"discovered_at,omitempty"`
	Collector       *UsageCollectorRuntime `json:"collector,omitempty"`
	Capabilities    []string               `json:"capabilities"`
}

NodeProfileRuntime is the vpn-core per-node runtime view (design-12 S4): the operator-facing "is this node under vpn-core management, what core/version is on it, is the config applied, is the collector healthy, what was last probed" page. It is a DERIVED read-model unioning the Lattice ProxyNodeProfile (managed config + apply/collector status) with the live discovered SingBoxInventory (core version + discovered node count + discovery status). A node appears if it has either.

type Options

type Options struct {
	Store *store.Store
	WebFS fs.FS
	// LogStore is the dedicated bounded log-line database (logs.db). Nil disables
	// the log-ingestion feature: its endpoints return 503 and agents are told to
	// tail nothing. Injected by main (opened beside the state file with the same
	// cipher), mirroring Store.
	LogStore      *logstore.Store
	AdminUsername string
	AdminPassword string
	Build         BuildInfo
	SecureCookies bool
	// TrustProxy enables reading the client address from proxy headers
	// (CF-Connecting-IP, then X-Forwarded-For). Only enable when the server
	// sits behind a trusted reverse proxy / Cloudflare; otherwise clients can
	// spoof the header and evade per-IP rate limiting.
	TrustProxy bool
	// RequireTOTP forces interactive user sessions to enable TOTP before they can
	// use non-setup APIs. Existing password/SSO login still issues a session so
	// the operator can enroll, but withAuth gates every other route until TOTP is
	// active. Bearer PATs are not interactive sessions and are unaffected.
	RequireTOTP bool
	// PluginDir is the root directory of installed plugin bundles. Empty disables
	// plugin loading entirely.
	PluginDir string
	// PluginTrust is the operator policy used to verify plugin signatures at load
	// time. The zero value is fail-closed: host-risk plugins require a trusted
	// publisher signature.
	PluginTrust plugin.TrustPolicy
	// PluginRuntimeDir, when set, enables the Tier-2 system runner: each system
	// plugin gets a confined 0700 working dir under this path and its verified
	// artifact is executed there (design-08). Empty keeps the noop runner (broker
	// armed, artifact NOT executed) — the deliberate default.
	PluginRuntimeDir string
	// PluginRuntimeEnv is the explicit environment-variable allowlist forwarded
	// to Tier-2 system plugins. Empty means plugins receive only the runner's
	// fixed safe PATH/HOME/TMPDIR.
	PluginRuntimeEnv []string
	// PublicURL is the externally-reachable base URL of this server (scheme +
	// host, no trailing slash), used to build the OIDC redirect URL. Required
	// for SSO login; empty disables the OIDC start/callback flow. It is also the
	// canonical source for the WebAuthn relying-party ID and origin (RPID = host,
	// RPOrigin = scheme://host[:port]); passkeys fail closed when it is empty.
	PublicURL string
	// MetricsToken enables the /metrics endpoint when non-empty. The endpoint
	// accepts only Authorization: Bearer <token>; empty keeps it hidden so public
	// deployments do not expose fleet runtime counters by default.
	MetricsToken string
	// CoreDNSBinary optionally pins the CoreDNS executable that self-host DNS
	// apply scripts may install. Empty preserves the fail-closed precondition
	// that coredns already exists on the node.
	CoreDNSBinary selfdns.CoreDNSBinarySource
	// GeoResolver maps node public IPs to advisory coordinates for the Fleet Map.
	// Nil keeps automatic lookup disabled; manual NodeGeo remains available.
	GeoResolver geoip.Resolver
	// AgentReleaseRepo is the trusted GitHub repository used by the simplified
	// node-agent update UX. Empty uses LatticeNet/lattice-node-agent.
	AgentReleaseRepo string
	// AuditHeadShipping periodically POSTs the verified, locally anchored audit
	// WAL head to an operator-controlled HTTPS endpoint. Empty URL disables it.
	AuditHeadShipping AuditHeadShippingOptions
	// TaskExecutionDisabled is a server-side fleet kill switch. When true, new
	// tasks are not queued and agents receive no task leases. Already leased
	// task results are still accepted so in-flight work can report terminal state.
	TaskExecutionDisabled bool
	// RenewalReminderInterval controls the machine-renewal reminder scheduler.
	// Zero uses the production default. DisableRenewalScheduler is intended for
	// tests that need full control over reminder evaluation.
	RenewalReminderInterval time.Duration
	DisableRenewalScheduler bool
	Logger                  *log.Logger
}

type Server

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

func New

func New(opts Options) (*Server, error)

func (*Server) Handler

func (s *Server) Handler() http.Handler

type SubscriptionSummary added in v0.2.0

type SubscriptionSummary struct {
	UserID          string `json:"user_id"`
	Email           string `json:"email,omitempty"`
	Enabled         bool   `json:"enabled"`
	Eligible        bool   `json:"eligible"` // enabled AND not expired
	HasSubToken     bool   `json:"has_sub_token"`
	BindingCount    int    `json:"binding_count"`
	CredentialCount int    `json:"credential_count"`
	ExpiresAt       string `json:"expires_at,omitempty"`
}

SubscriptionSummary is the producer-side, per-identity subscription state (design-12 S5). The locked boundary: vpn-core PRODUCES the source (identities, credentials, line bindings, a sub token) and Sub-Store COMBINES + PUBLISHES the actual delivery. So this read-model intentionally exposes only subscription STATE (eligibility, binding/credential counts, whether a sub token exists) — NOT the raw sub token or rendered links, which remain with the legacy /sub substrate and the Sub-Store publisher. The dashboard renders a thin view of this and points the operator at Sub-Store for publishing.

type UsageByNode added in v0.2.0

type UsageByNode struct {
	NodeID    string `json:"node_id"`
	NodeName  string `json:"node_name,omitempty"`
	UsedBytes int64  `json:"used_bytes"`
	UserCount int    `json:"user_count"`
	At        string `json:"at,omitempty"`
}

type UsageByUser added in v0.2.0

type UsageByUser struct {
	UserID     string `json:"user_id"`
	Email      string `json:"email,omitempty"`
	UsedBytes  int64  `json:"used_bytes"`
	QuotaBytes int64  `json:"quota_bytes,omitempty"`
	Status     string `json:"status,omitempty"`
	LastSeen   string `json:"last_seen,omitempty"`
}

Usage is the vpn-core 3-D usage read-model (design-12 S3). It presents traffic from two operator-facing dimensions — by user and by node — plus the per-(node, user) breakdown. It is DERIVED on demand from the existing accounting substrate: ProxyUser.UsedBytes (monotonic per-user total) and the latest ProxyUsageSnapshot per node (raw per-(node,user) counters), mapped onto VpnUser identities.

S3b line-aware collectors populate line_user_bytes in ProxyUsageSnapshot; older collectors continue to produce aggregate rows with line_hash_id empty.

type UsageCollector added in v0.2.0

type UsageCollector struct {
	NodeID    string `json:"node_id"`
	NodeName  string `json:"node_name,omitempty"`
	Source    string `json:"source,omitempty"`
	Status    string `json:"status,omitempty"`
	Error     string `json:"error,omitempty"`
	CheckedAt string `json:"checked_at,omitempty"`
}

type UsageCollectorRuntime added in v0.2.0

type UsageCollectorRuntime struct {
	Source    string `json:"source,omitempty"`
	Status    string `json:"status,omitempty"`
	CheckedAt string `json:"checked_at,omitempty"`
	LastOKAt  string `json:"last_ok_at,omitempty"`
	LastError string `json:"last_error,omitempty"`
}

type UsageRow added in v0.2.0

type UsageRow struct {
	NodeID     string `json:"node_id"`
	NodeName   string `json:"node_name,omitempty"`
	UserID     string `json:"user_id"`
	Email      string `json:"email,omitempty"`
	LineHashID string `json:"line_hash_id,omitempty"` // empty until S3b sb-stats collector
	Bytes      int64  `json:"bytes"`
}

type VpnCredential added in v0.2.0

type VpnCredential struct {
	Protocol string `json:"protocol"`           // vless|vmess|trojan|shadowsocks|hysteria2|tuic|anytls
	UUID     string `json:"uuid,omitempty"`     // vless/vmess/tuic
	Password string `json:"password,omitempty"` // trojan/shadowsocks/hysteria2/anytls
	Flow     string `json:"flow,omitempty"`     // vless xtls flow
	Method   string `json:"method,omitempty"`   // shadowsocks cipher
	Security string `json:"security,omitempty"` // vmess security
}

VpnCredential is one per-protocol credential. Only the fields relevant to the protocol are populated. uuid/password are secret material.

type VpnUser added in v0.2.0

type VpnUser struct {
	ID          string          `json:"id"`
	Email       string          `json:"email"`
	Name        string          `json:"name,omitempty"`
	Enabled     bool            `json:"enabled"`
	Credentials []VpnCredential `json:"credentials"`
	Bindings    []LineBinding   `json:"bindings"`
	SubID       string          `json:"sub_id,omitempty"`
	QuotaBytes  int64           `json:"quota_bytes,omitempty"`
	ExpiresAt   time.Time       `json:"expires_at,omitempty"`
	Group       string          `json:"group,omitempty"`
	Comment     string          `json:"comment,omitempty"`

	// MigratedFromProxyUser records the legacy ProxyUser this identity was derived
	// from, so the migration is idempotent and the subscription substrate is traceable.
	MigratedFromProxyUser string `json:"migrated_from_proxy_user,omitempty"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

VpnUser is the vpn-core identity model (design-12 S2): one human/account identity that carries a credential SET (per protocol) and is bound to many Lines. It is OWNED by the vpn-core plugin — persisted in the plugin's durable KV bucket (plugin:latticenet.vpn-core), not the SDK-typed store — so it is genuinely plugin-owned data with no SDK release coupling. It is additive: the legacy model.ProxyUser stays as the subscription-render + usage-accounting substrate this slice; VpnUsers are derived from ProxyUsers by an idempotent migration.

Credential secrets (uuid/password) are NEVER returned through the read RPC; the gateway-facing views are redacted (see vpnUserView).

Jump to

Keyboard shortcuts

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