web

package
v1.0.48 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 59 Imported by: 0

Documentation

Overview

Package web is loft-panel's HTTP side: sign-in, the JSON API under /api/, and the embedded UI. It runs without privileges; anything that touches the node goes through loft-panel-adm.

loft-panel is the web admin for a loft server. The node is loft-node, the proxy daemon the panel manages. loft-panel-adm (or "panel-adm") is a small helper that runs as root and does the privileged work: editing node files, restarting services, installing packages. The panel talks to it over a Unix socket with package admproto (one JSON request, one JSON reply); here that is the Adm interface, reached through Server.Adm.

Routes: Server.Handler in web.go lists every /api/ route in one place, each wrapped in need, which checks who is calling. Machine description of the same table: docs/panel-api.yaml (OpenAPI 3.1). A caller signs in with a session cookie (state-changing requests then also send the session's CSRF token) or uses an API token in "Authorization: Bearer". Each route names the panel areas (members, network, mail, ...) and the level (view or change) the caller's role must have; the owner role passes all. Successful changes are written to the audit log.

Each feature lives in its own file (mail.go, users.go, relays.go, ...), with its handlers and helpers. The browser UI is the static files in the ui/ directory, embedded into the binary at build time; Server.UIDir serves them from disk instead during development.

Index

Constants

View Source
const (
	EventCert   = "cert"   // a certificate ends in 14 days
	EventUpdate = "update" // an update was installed or rolled back
	EventNode   = "node"   // loft-node is not running
	EventBackup = "backup" // a scheduled backup failed
)

Events a letter can be about.

View Source
const LetsEncrypt = "https://acme-v02.api.letsencrypt.org/directory"

LetsEncrypt is the production ACME directory.

View Source
const ReleasesAPI = "https://api.github.com/repos/a3app/loft/releases?per_page=30"

ReleasesAPI lists the project's releases.

Variables

View Source
var CloudflareIPs = []string{"https://www.cloudflare.com/ips-v4", "https://www.cloudflare.com/ips-v6"}

CloudflareIPs are Cloudflare's published ranges.

View Source
var RecordTypes = []string{"A", "AAAA", "CNAME", "MX", "TXT", "CAA", "SRV", "NS"}

RecordTypes the panel edits.

Functions

func ServerIPs

func ServerIPs() []net.IP

ServerIPs are this host's public unicast addresses.

func SessionLimits added in v1.0.21

func SessionLimits(st store.Settings) (idle, max time.Duration)

SessionLimits turns the stored choice into durations (defaults 30m, 7d). "off" idles until Max.

Types

type ACME

type ACME struct {
	Dir string // data directory: acme-account.pem lives here
	URL string // ACME directory; empty = Let's Encrypt
	// contains filtered or unexported fields
}

ACME issues certificates with HTTP-01. nginx on :80 passes /.well-known/acme-challenge/ to the panel, which answers from tokens.

func (*ACME) Issue

func (a *ACME) Issue(ctx context.Context, name, email string) (Issued, error)

Issue gets a certificate for name from the ACME directory (HTTP-01).

func (*ACME) IssueNames added in v1.0.22

func (a *ACME) IssueNames(ctx context.Context, names []string, email string, dns DNS01) (Issued, error)

IssueNames gets one certificate for names; with dns it proves them by DNS-01 (needed for *.names and names that do not point here), else by HTTP-01 through nginx on :80.

func (*ACME) Preflight

func (a *ACME) Preflight(ctx context.Context, name string) error

Preflight checks what Let's Encrypt will check, with clearer errors: the name points at this server, and http://name/.well-known/… reaches the panel.

type Adm

type Adm interface {
	Call(ctx context.Context, op string, body, out any) error
}

Adm is the part of admproto.Client the panel uses; tests swap it.

type Cloudflare added in v1.0.22

type Cloudflare struct {
	Token string
	Base  string // tests
	HTTP  *http.Client
	// contains filtered or unexported fields
}

Cloudflare is the Cloudflare API v4 with an API token (Zone.DNS — Edit).

func (*Cloudflare) Check added in v1.0.22

func (c *Cloudflare) Check(ctx context.Context) error

Check asks Cloudflare whether the token is valid.

func (*Cloudflare) Create added in v1.0.22

func (c *Cloudflare) Create(ctx context.Context, zone string, r Record) (string, error)

Create adds a record and returns its new id.

func (*Cloudflare) Delete added in v1.0.22

func (c *Cloudflare) Delete(ctx context.Context, zone, rid string) error

Delete removes the record with id rid.

func (*Cloudflare) Records added in v1.0.22

func (c *Cloudflare) Records(ctx context.Context, zone string) ([]Record, error)

Records lists a zone's records (up to 500) in the panel's form: relative names, TTL 0 for automatic, CAA/SRV joined back into one value string, TXT without surrounding quotes.

func (*Cloudflare) Update added in v1.0.22

func (c *Cloudflare) Update(ctx context.Context, zone string, r Record) error

Update replaces the record with id r.ID.

func (*Cloudflare) Zones added in v1.0.22

func (c *Cloudflare) Zones(ctx context.Context) ([]string, error)

Zones lists the account's zones (up to 50) and remembers their ids, because every record call needs the zone id, not its name.

type DNS01 added in v1.0.22

type DNS01 func(ctx context.Context, fqdn, value string) (cleanup func(), err error)

DNS01 publishes a TXT record value at fqdn for an ACME dns-01 check and returns how to take it away.

type DNSProvider added in v1.0.22

type DNSProvider interface {
	Check(ctx context.Context) error
	Zones(ctx context.Context) ([]string, error)
	Records(ctx context.Context, zone string) ([]Record, error)
	Create(ctx context.Context, zone string, r Record) (string, error)
	Update(ctx context.Context, zone string, r Record) error
	Delete(ctx context.Context, zone string, id string) error
}

DNSProvider is what the panel needs from a provider.

type DigitalOcean added in v1.0.22

type DigitalOcean struct {
	Token string
	Base  string
	HTTP  *http.Client
}

DigitalOcean is the DigitalOcean API v2 with a token that may write.

func (*DigitalOcean) Check added in v1.0.22

func (d *DigitalOcean) Check(ctx context.Context) error

Check proves the token works by reading the account.

func (*DigitalOcean) Create added in v1.0.22

func (d *DigitalOcean) Create(ctx context.Context, zone string, r Record) (string, error)

Create adds a record and returns its new id.

func (*DigitalOcean) Delete added in v1.0.22

func (d *DigitalOcean) Delete(ctx context.Context, zone, id string) error

Delete removes the record with the given id.

func (*DigitalOcean) Records added in v1.0.22

func (d *DigitalOcean) Records(ctx context.Context, zone string) ([]Record, error)

Records lists a zone's records (up to 200) in the panel's form, joining CAA and SRV parts back into one value string.

func (*DigitalOcean) Update added in v1.0.22

func (d *DigitalOcean) Update(ctx context.Context, zone string, r Record) error

Update replaces the record with id r.ID.

func (*DigitalOcean) Zones added in v1.0.22

func (d *DigitalOcean) Zones(ctx context.Context) ([]string, error)

Zones lists the account's domains (up to 200), sorted.

type Issued

type Issued struct {
	Fullchain string
	Key       string
	NotAfter  time.Time
}

Issued is a fresh certificate.

type Namecheap added in v1.0.22

type Namecheap struct {
	User, Key, ClientIP string
	Base                string
	HTTP                *http.Client
}

Namecheap is the Namecheap XML API: the user's API key, the API user, and the server's public IP on the account's allowlist. It can only replace a zone's records as a whole (setHosts), so every change reads the list, edits it and writes it all back. A record's ID is Namecheap's HostId: Namecheap keeps it for a record that is written back unchanged, so it stays valid when other records come and go. (Earlier versions used the record's position in the list, which moved whenever a record before it was deleted; reconcileOurs repairs ids saved that way.)

func (*Namecheap) Check added in v1.0.22

func (n *Namecheap) Check(ctx context.Context) error

Check proves the credentials and the IP allowlist work by listing domains.

func (*Namecheap) Create added in v1.0.22

func (n *Namecheap) Create(ctx context.Context, zone string, r Record) (string, error)

Create reads the zone, appends r and writes the whole zone back. Namecheap gives the new record its HostId only when it saves it, so the zone is read once more to find it: the record of r's type, name and value that was not there before. If it cannot be told apart (an exact copy already existed), the id is empty and the panel finds the record by type and name later.

func (*Namecheap) Delete added in v1.0.22

func (n *Namecheap) Delete(ctx context.Context, zone, id string) error

Delete reads the zone, drops the record with id and writes the rest back.

func (*Namecheap) Records added in v1.0.22

func (n *Namecheap) Records(ctx context.Context, zone string) ([]Record, error)

Records lists a zone's records. A record's id is its HostId (a host without one, which Namecheap does not send, gets "#" and its position), and TTL 1799 (Namecheap's automatic) is shown as 0.

func (*Namecheap) Update added in v1.0.22

func (n *Namecheap) Update(ctx context.Context, zone string, r Record) error

Update reads the zone, replaces the record with r.ID and writes the whole zone back.

func (*Namecheap) Zones added in v1.0.22

func (n *Namecheap) Zones(ctx context.Context) ([]string, error)

Zones lists the account's domains (up to 100).

type Record added in v1.0.22

type Record struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	Name     string `json:"name"`
	Value    string `json:"value"`
	Priority int    `json:"priority,omitempty"`
	TTL      int    `json:"ttl,omitempty"`
}

Record is one DNS record.

type Server

type Server struct {
	Store    *store.Store
	Sessions *auth.Sessions
	Limit    *auth.Limiter
	// Slow replaces Limit when the client address is unknown (see knownIP).
	Slow *auth.Slow
	Adm  func(by string) Adm
	// Hosts the panel answers to besides loopback; empty answers to any.
	Hosts []string

	// Settings is the wizard's state; ACME issues certificates.
	Settings *store.SettingsFile
	ACME     *ACME

	// ReleasesAPI and HTTP are for following GitHub releases (tests).
	ReleasesAPI string
	HTTP        *http.Client
	// Audit is the log of changes (Users → Log).
	Audit *store.Audit
	// SendMail replaces SMTP (tests).
	SendMail func(n store.Notify, subject, body string) error
	// SetupCode must be sent with the first owner while the store is empty;
	// SetupFile holds it on disk and is removed once the owner exists.
	SetupCode string
	SetupFile string
	// UIDir serves the UI from disk instead of the embedded copy (development).
	UIDir string
	Log   *log.Logger
	// contains filtered or unexported fields
}

Server is one panel instance.

func (*Server) CheckReleases added in v1.0.21

func (s *Server) CheckReleases(ctx context.Context) (store.Settings, error)

CheckReleases asks GitHub for the newest release and records it in the settings, together with the check time or the error.

func (*Server) FollowReleases added in v1.0.21

func (s *Server) FollowReleases(ctx context.Context)

FollowReleases checks every six hours and, in auto mode, starts the update inside the window. A release that failed is not retried for a day. It wakes every 10 minutes and runs until ctx ends.

func (*Server) Handler

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

Handler returns the full HTTP handler: every API route with its access rule, the ACME challenge path, and the UI files for everything else, all behind guard.

func (*Server) LoadGuard added in v1.0.22

func (s *Server) LoadGuard()

LoadGuard applies the saved guard settings at start.

func (*Server) Renew

func (s *Server) Renew(ctx context.Context)

Renew keeps the certificate fresh: every 12 h, 30 days before expiry.

func (*Server) SetBackupDir added in v1.0.22

func (s *Server) SetBackupDir(dir string)

SetBackupDir is the panel's data directory: backup.json and backup/.

func (*Server) SetDomainsFile added in v1.0.22

func (s *Server) SetDomainsFile(dir string)

SetDomainsFile is where zones and certificates are kept.

func (*Server) SetSeenFile added in v1.0.21

func (s *Server) SetSeenFile(dir string)

SetSeenFile is where the last-seen times are kept (data dir).

func (*Server) Watch added in v1.0.21

func (s *Server) Watch(ctx context.Context)

Watch sends event letters: a certificate ending in 14 days, an update installed or rolled back, loft-node down for two checks in a row.

Jump to

Keyboard shortcuts

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