federation

package
v0.12.1 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const MinTokenLen = 16

MinTokenLen is the shortest accepted peer token (the peer's RDPANEL_FEDERATION_TOKEN has the same minimum).

Variables

View Source
var ErrNoToken = errors.New("federation: no stored token for this peer")

ErrNoToken means a peer has no stored token (it was registered by a version that kept tokens in memory only): delete and re-add it.

Functions

func HashToken

func HashToken(token string) string

HashToken computes sha256 hex string for the peer auth token.

func NormalizeAPIURL added in v0.11.0

func NormalizeAPIURL(raw string) (string, *url.URL, error)

NormalizeAPIURL validates a peer base URL (http(s)://host[:port][/prefix], no credentials, query or fragment) and trims trailing slashes.

Types

type Config

type Config struct {
	Store        *Store
	Relays       RelaySource
	Version      string
	SyncInterval time.Duration
	Log          *slog.Logger
	// InboundToken is the bearer token peers must present to this panel's
	// federation endpoints (RDPANEL_FEDERATION_TOKEN). Empty refuses all.
	InboundToken string
	// AllowPrivate reports whether peers may live on private, loopback or
	// link-local addresses (the relays "allow private hosts" option).
	// nil: never.
	AllowPrivate func(context.Context) bool
	// HTTPClient overrides the outgoing client (tests). The default refuses
	// private addresses at dial time (unless AllowPrivate), ignores proxy
	// variables and does not follow redirects.
	HTTPClient *http.Client
	// Lookup resolves peer host names for the registration check
	// (default net.DefaultResolver.LookupNetIP).
	Lookup func(ctx context.Context, network, host string) ([]netip.Addr, error)
}

Config configures the federation service.

type CreatePeerInput

type CreatePeerInput struct {
	Name       string
	APIURL     string
	AuthToken  string
	SyncRelays bool
}

CreatePeerInput is input for registering a new peer panel.

type FederatedRelay

type FederatedRelay struct {
	ID         int64     `json:"id"`
	PeerID     int64     `json:"peer_id"`
	PeerName   string    `json:"peer_name,omitempty"`
	RemoteName string    `json:"remote_name"`
	PublicHost string    `json:"public_host"`
	Region     string    `json:"region,omitempty"`
	Health     string    `json:"health"`
	LastSyncAt time.Time `json:"last_sync_at"`
}

FederatedRelay represents a relay announced by a peered RD Panel.

type HealthDTO

type HealthDTO struct {
	Status        string `json:"status"`
	Version       string `json:"version"`
	ActiveRelays  int    `json:"active_relays"`
	TimestampNano int64  `json:"timestamp_nano"`
}

HealthDTO is the response to /api/v1/federation/health.

type Peer

type Peer struct {
	ID         int64      `json:"id"`
	Name       string     `json:"name"`
	APIURL     string     `json:"api_url"`
	TokenHash  string     `json:"-"`
	SyncRelays bool       `json:"sync_relays"`
	Status     PeerStatus `json:"status"`
	LastSyncAt *time.Time `json:"last_sync_at,omitempty"`
	LastError  *string    `json:"last_error,omitempty"`
	CreatedAt  time.Time  `json:"created_at"`
	UpdatedAt  time.Time  `json:"updated_at"`
}

Peer represents an external peered RD Panel instance.

type PeerStatus

type PeerStatus string

PeerStatus is the connection status of a peered RD Panel.

const (
	StatusUnknown PeerStatus = "unknown"
	StatusActive  PeerStatus = "active"
	// StatusUnreachable marks a peer whose last sync failed: unreachable,
	// token rejected, or an invalid answer. Peer.LastError says which.
	StatusUnreachable PeerStatus = "unreachable"
)

type PublicRelayDTO

type PublicRelayDTO struct {
	Name       string `json:"name"`
	PublicHost string `json:"public_host"`
	Region     string `json:"region,omitempty"`
	Health     string `json:"health"`
}

PublicRelayDTO is what a panel announces to peers.

type RelaySource

type RelaySource interface {
	List(ctx context.Context) ([]relays.View, relays.Rotation, error)
}

RelaySource provides active local relays to announce.

type Service

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

Service manages federation peering, relay synchronization and public federation endpoints.

func NewService

func NewService(cfg Config) *Service

NewService creates a new federation service.

func (*Service) Authorized added in v0.11.0

func (s *Service) Authorized(r *http.Request) bool

Authorized reports whether r carries this panel's federation token. The comparison is constant-time over SHA-256 digests.

func (*Service) CreatePeer added in v0.11.0

func (s *Service) CreatePeer(ctx context.Context, in CreatePeerInput) (Peer, error)

CreatePeer validates and registers a peer. Unless private peers are allowed, an api_url pointing at a private, loopback or link-local address (literally or via DNS) is refused.

func (*Service) PublicHealth

func (s *Service) PublicHealth(ctx context.Context) HealthDTO

PublicHealth returns local health for peering verification.

func (*Service) PublicRelays

func (s *Service) PublicRelays(ctx context.Context) ([]PublicRelayDTO, error)

PublicRelays returns local active relays for peering peers.

func (*Service) RegisterPublic added in v0.11.0

func (s *Service) RegisterPublic(r chi.Router, limiter auth.Limiter)

RegisterPublic mounts GET /health and GET /relays (under /api/v1/federation). Both require the federation bearer token; failed attempts back off per client IP through limiter (nil: no limit).

func (*Service) Run added in v0.11.0

func (s *Service) Run(ctx context.Context)

Run is the background sync loop (an app worker); it returns when ctx ends.

func (*Service) Store

func (s *Service) Store() *Store

Store returns the underlying store.

func (*Service) SyncAll

func (s *Service) SyncAll(ctx context.Context)

SyncAll passes through all peers and attempts sync.

func (*Service) SyncPeer

func (s *Service) SyncPeer(ctx context.Context, id int64) error

SyncPeer checks a peer's health and, with sync_relays, imports the relays it announces. Any failure (unreachable, non-200, invalid or inconsistent answer) marks the peer unreachable with a short reason; the returned error's text is that reason.

type Store

type Store struct {
	DB *db.DB
	// AEAD seals peer tokens (required by Create and Token).
	AEAD *crypto.AEAD
	Now  func() time.Time
}

Store persists federation peers and announced relays.

The token this panel presents to a peer is needed in plaintext for every sync, so it is kept AEAD-sealed in the panel settings under "federation.peer.<id>.token" (crypto.FederationPeerTokenAD); the federation_peers.token_hash column only holds its SHA-256.

func (*Store) Create

func (s *Store) Create(ctx context.Context, in CreatePeerInput) (Peer, error)

Create registers a new peered panel and stores its token sealed.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, id int64) error

Delete removes a peer, its stored token and its announced relays (via CASCADE).

func (*Store) Get

func (s *Store) Get(ctx context.Context, id int64) (Peer, error)

Get returns one peer by ID.

func (*Store) List

func (s *Store) List(ctx context.Context) ([]Peer, error)

List returns all registered peers.

func (*Store) ListFederatedRelays

func (s *Store) ListFederatedRelays(ctx context.Context) ([]FederatedRelay, error)

ListFederatedRelays returns all federated relays from all active peers. They are shown for visibility only: nothing adds them to hbbs' rotation.

func (*Store) ReplaceFederatedRelays

func (s *Store) ReplaceFederatedRelays(ctx context.Context, peerID int64, relays []FederatedRelay) error

ReplaceFederatedRelays atomically replaces the relays associated with a peer.

func (*Store) Token added in v0.11.0

func (s *Store) Token(ctx context.Context, id int64) (string, error)

Token returns the token this panel presents to peer id (ErrNoToken when none is stored).

func (*Store) UpdateStatus

func (s *Store) UpdateStatus(ctx context.Context, id int64, status PeerStatus, errMsg *string) error

UpdateStatus records a peer's sync attempt and current connectivity status.

Jump to

Keyboard shortcuts

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