web

package
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 62 Imported by: 0

Documentation

Overview

Package web is the admin panel: server-rendered html/template pages with htmx partial swaps, session cookie auth, per-request CSRF tokens, and a strict content security policy. Handlers call domain services directly — the REST API is never in the request path (docs/architecture/ project-structure.md: api/web → services).

Security posture (docs/operations/security.md): session tokens are hashed at rest by internal/auth; the CSRF token is HMAC-derived from the session token so it needs no storage; scripts/styles are same-origin only (no inline script/style survive CSP); secrets never reach templates.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Deps

type Deps struct {
	DB          *database.DB
	Sessions    *auth.SessionStore
	Admins      *admin.Service
	Resellers   *reseller.Service
	Settings    *settings.Registry
	Ring        *secrets.KeyRing
	Audit       *audit.Service
	Users       *user.Service
	Devices     *device.Service
	Plans       *plan.Service
	Integration *integration.Service
	Ifaces      *iface.Service
	// ProfileGenerator is the canonical server-side profile preview seam.
	// It defaults to Ifaces.GenerateProfile; tests may replace it to exercise
	// entropy failures without weakening the production generator.
	ProfileGenerator func(iface.ProfilePolicy) (iface.Obfuscation, error)
	Accounting       *accounting.Service
	Log              *slog.Logger

	// Reconciler runs the complete serialized network pass after structural
	// mutations (see api.Server).
	Reconciler accounting.Reconciler
	NodeStatus func(context.Context, time.Time) nodestatus.Snapshot

	// ClientConf renders client configs + QR (shared with the REST API).
	ClientConf *clientconf.Renderer

	// Links serves the per-user subscription links (public /sub/ surface).
	Links *subscription.Service

	// Backup is the archive engine (panel + CLI only — ADR-0007). Wired
	// from serve; nil in tests that don't exercise the ops screens.
	Backup *backup.Service
	// UpdateQueue is the data-volume side of the fixed host-owned lifecycle
	// broker. UpdateCatalog supplies published stable versions on demand.
	UpdateQueue   *updatequeue.Queue
	UpdateCatalog ReleaseCatalog
	DomainQueue   *domainqueue.Queue
	DomainPolicy  domaintls.Snapshot

	// Tokens and Webhooks are the same instances the REST API uses — one
	// business layer, two surfaces.
	Tokens   *token.Service
	Webhooks *webhook.Service

	// Telemetry is the scheduler-owned immutable live history. Dashboard
	// requests never invoke its source.
	Telemetry *telemetry.Sampler

	Version      string
	TLSMode      config.TLSMode
	NodeID       string
	ToolsVersion string
}

Deps wires the services the panel renders. The same instances the REST API uses are passed in — one business layer, two surfaces.

type ReleaseCatalog

type ReleaseCatalog interface {
	Releases(context.Context) ([]distribution.Release, error)
}

type Server

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

Server is the admin panel.

func New

func New(d Deps) (*Server, error)

New builds the panel: parse templates once, hash assets once.

func (*Server) Handler

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

Handler returns the panel mux. It is mounted at "/" by serve; the REST API, health endpoints and /metrics keep their own root-level patterns.

type View

type View struct {
	Locale       i18n.Locale
	Dir          string
	Theme        string // "light" | "dark" | "system"
	Preset       string // allowlisted visual preset ID; empty/unknown resolves to built-in
	Digits       i18n.DigitStyle
	Path         string // request path, for nav highlighting
	PageClass    string // content width tier (" content--narrow" on form/settings routes)
	SubLayout    string // public subscription composition, absent on error surfaces
	Admin        *auth.Admin
	CSRF         string
	Version      string
	UpdateNotice bool
	LoginContext url.Values

	// ToastMsg carries a post-redirect-flash message (already localized).
	ToastMsg   string
	ToastError bool

	// Data carries the page-specific payload (typed per page).
	Data any
	// contains filtered or unexported fields
}

View is the render context for every template execution. Locale-scoped helpers are methods so templates stay i18n-aware without global state.

func (*View) A

func (v *View) A(name string) string

A returns the cache-busted URL for an embedded static asset, e.g. {{.A "/css/app.css"}}.

func (*View) B

func (v *View) B(n int64) string

B formats a byte count with locale units.

func (*View) BLim

func (v *View) BLim(limit *int64) string

BLim renders a byte limit ("unlimited" when nil).

func (*View) BLimParts added in v0.1.1

func (v *View) BLimParts(limit *int64) byteParts

func (*View) BParts added in v0.1.1

func (v *View) BParts(n int64) byteParts

BParts keeps a Latin numeral and its localized unit as separate visual atoms. This lets an RTL flex row preserve natural number → unit order.

func (*View) Can

func (v *View) Can(scope string) bool

Can reports whether the signed-in admin may use a scope-gated surface (owners always pass). The nav renders accordingly; the server enforces regardless (security.md: the UI never hides what the server doesn't enforce — this is the polite direction, not the security one).

func (*View) CompactAuditID

func (v *View) CompactAuditID(value string) string

CompactAuditID shortens UUID-shaped identifiers only. Human names, addresses and other meaningful target values retain their exact presentation.

func (*View) D

func (v *View) D(t *time.Time) string

D renders a date ("never" when nil).

func (*View) DT

func (v *View) DT(t *time.Time) string

func (*View) DateTime

func (v *View) DateTime(t time.Time) string

DT renders a date with time.

func (*View) DeliveryError

func (v *View) DeliveryError(message string) string

func (*View) Dur

func (v *View) Dur(sec int64) string

Dur renders a duration in seconds.

func (*View) DurLim added in v0.1.4

func (v *View) DurLim(sec *int64) string

DurLim renders a stored optional duration for template previews.

func (*View) DurUnit

func (v *View) DurUnit(secs *int64) string

DurUnit is the matching unit for DurVal.

func (*View) DurVal

func (v *View) DurVal(secs *int64) string

DurVal renders a duration for a value+unit form input: whole months when the duration is a multiple of 30 days, else whole days, else hours.

func (*View) Elapsed added in v0.1.7

func (v *View) Elapsed(start, end time.Time) string

func (*View) ExpiryClass

func (v *View) ExpiryClass(t *time.Time) string

ExpiryClass colors imminent (warn) and passed (danger) expiries.

func (*View) HasChoice

func (v *View) HasChoice(values []string, value string) bool

func (*View) Human added in v0.1.8

func (v *View) Human(text string) string

Human formats a previously humanized metric or date string. Machine values and input values use their original typed fields, never this display helper.

func (*View) Icon

func (v *View) Icon(name string) template.HTML

Icon renders a sprite reference. Icons are recognition aids, never decoration; text labels stay in markup next to them.

func (*View) IconS

func (v *View) IconS(name string) template.HTML

IconS is the small variant (inline in dense rows).

func (*View) Initial

func (v *View) Initial(name string) string

Initial keeps a multibyte account name intact in the shared avatar.

func (*View) IsActive

func (v *View) IsActive(section string) bool

IsActive reports whether the current path belongs to a nav section.

func (*View) KD

func (v *View) KD(n *int) string

KD renders a kbps limit for form inputs ("" when nil).

func (v *View) LocaleLink() string

func (*View) MeterClass

func (v *View) MeterClass(used int64, limit *int64) string

MeterClass picks the nearest width step (CSP forbids inline styles) and the tone class for a used/limit pair; limit == nil renders full bar.

func (*View) N

func (v *View) N(n int64) string

N formats an integer with grouping.

func (*View) OpsLabel

func (v *View) OpsLabel(kind, value string) string

func (*View) OpsTimestamp

func (v *View) OpsTimestamp(t time.Time) string

func (*View) QuotaUnit

func (v *View) QuotaUnit(b *int64) string

QuotaUnit is the matching unit for QuotaVal ("mb" below 1 GB, else "gb").

func (*View) QuotaVal

func (v *View) QuotaVal(b *int64) string

QuotaVal renders a byte limit as a decimal number for a form input, choosing the more readable unit: MB below 1 GB, GB otherwise. nil = "".

func (*View) Rel

func (v *View) Rel(t *time.Time) string

Rel renders relative time ("never" when nil).

func (*View) RelIn

func (v *View) RelIn(t *time.Time) string

RelIn renders a future-relative hint ("in 3 days") for expiry columns; past dates fall back to the past-relative form.

func (*View) ScopeDescription

func (v *View) ScopeDescription(value string) string

func (*View) ScopeLabel

func (v *View) ScopeLabel(value string) string

func (*View) ScopePresetTier added in v0.1.4

func (v *View) ScopePresetTier(scope string) string

func (*View) St

func (v *View) St(status string) string

St renders a localized lifecycle status label.

func (*View) StClass

func (v *View) StClass(status string) string

StClass maps a status to its badge tone class.

func (*View) StatusTone added in v0.1.10

func (v *View) StatusTone(state nodestatus.State) string

func (*View) T

func (v *View) T(key string, args ...any) string

T translates key with the request's locale.

func (*View) TokenExpired

func (v *View) TokenExpired(t *time.Time) bool

func (*View) U

func (v *View) U(n *int) string

U renders a stored Kbps limit in the panel's MB/s unit.

func (*View) UnknownChoices

func (v *View) UnknownChoices(values []string) []string

Jump to

Keyboard shortcuts

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