middleware

package
v2.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// LauncherDashboardLocalAutoLoginPath is the one-shot local browser
	// bootstrap endpoint used by the launcher-managed auto-open flow.
	LauncherDashboardLocalAutoLoginPath = "/launcher-auto-login"
	// LauncherDashboardSetupPath is the setup page used before the dashboard
	// password is initialized.
	LauncherDashboardSetupPath = "/launcher-setup"
	// LauncherDashboardSetupTokenParam is the query parameter of the setup
	// page that carries the one-time setup token.
	LauncherDashboardSetupTokenParam = "token"
)
View Source
const APIBodyReadTimeout = 60 * time.Second

APIBodyReadTimeout bounds reading one request body. It is not a server-wide ReadTimeout: that one stays armed while the handler runs and cancels long requests (module installs, catalog syncs) once it passes.

View Source
const DashboardThemeScriptHash = "'sha256-R49sAvhnDYMkfDhvWDBUrx9TOFbwiKRoQrWcjzGQFsI='"

DashboardThemeScriptHash is the CSP hash of the inline script in web/frontend/index.html that applies the saved theme before first paint. The launcher hashes the inline scripts of the page it embeds at startup; this is the fallback when it cannot.

View Source
const DefaultAPIBodyLimit = 2 << 20

DefaultAPIBodyLimit bounds an /api request body unless the route reads a larger one itself.

View Source
const LauncherDashboardCookieName = "compa_launcher_auth"

LauncherDashboardCookieName is the HttpOnly cookie set after a successful password login.

Variables

View Source
var ErrInvalidLauncherDashboardGrant = errors.New("invalid launcher dashboard grant")

ErrInvalidLauncherDashboardGrant reports that an auto-login grant is missing, expired, already consumed, or otherwise invalid.

Functions

func APIBodyLimit

func APIBodyLimit(limit int64, larger map[string]int64, next http.Handler) http.Handler

APIBodyLimit caps /api request bodies at limit bytes. Routes in larger (exact paths) are capped at their own limit instead: they take uploads and check the size themselves. A body declared larger is refused at once. Reading a body must finish within APIBodyReadTimeout; the deadline is lifted once it is read.

func ClearLauncherDashboardSessionCookie

func ClearLauncherDashboardSessionCookie(w http.ResponseWriter, r *http.Request, secure func(*http.Request) bool)

ClearLauncherDashboardSessionCookie clears the dashboard session (e.g. logout).

func ContentSecurityPolicy

func ContentSecurityPolicy(scriptHashes []string) string

ContentSecurityPolicy is the dashboard's CSP. Remote https images stay allowed because the owner chooses whether chat shows them (remote_images); connect-src admits the web chat WebSocket.

func DefaultLauncherDashboardSecureCookie

func DefaultLauncherDashboardSecureCookie(r *http.Request) bool

DefaultLauncherDashboardSecureCookie mirrors typical production HTTPS detection (TLS or X-Forwarded-Proto).

func HostAllowlist

func HostAllowlist(cfg HostAllowlistConfig, next http.Handler) http.Handler

HostAllowlist answers only requests whose Host names this computer. A page on another site that rebinds its DNS name to this computer's address still sends its own name as Host, so it is refused before it reaches any endpoint, the first-run setup included. Ports are ignored: the Vite dev server proxies from localhost:5173.

func IPAllowlist

func IPAllowlist(cfg IPAllowlistConfig, next http.Handler) (http.Handler, error)

IPAllowlist restricts access to requests from configured CIDR ranges. Loopback addresses can optionally bypass CIDR checks for local administration. X-Forwarded-For is only trusted when the immediate peer is in a trusted CIDR. Empty CIDR list means no restriction.

func InlineScriptHashes

func InlineScriptHashes(html []byte) []string

InlineScriptHashes returns the CSP sources ('sha256-...') of the inline scripts in an HTML page, the ones without src, in page order.

func JSONContentType

func JSONContentType(next http.Handler) http.Handler

JSONContentType sets the Content-Type header to application/json for API requests handled by the wrapped handler.

func LauncherDashboardAuth

func LauncherDashboardAuth(cfg LauncherDashboardAuthConfig, next http.Handler) http.Handler

LauncherDashboardAuth requires a valid session cookie before calling next. Public paths are login/setup pages and /api/auth/* handlers.

func LauncherDashboardSetupURLPath

func LauncherDashboardSetupURLPath(token string) string

LauncherDashboardSetupURLPath returns the setup page path carrying token.

func Logger

func Logger(next http.Handler) http.Handler

Logger logs each HTTP request with method, path, status code, and duration.

func NewLauncherDashboardSessionCookie

func NewLauncherDashboardSessionCookie() (string, error)

NewLauncherDashboardSessionCookie creates the per-process session cookie value.

func NewLauncherDashboardSetupToken

func NewLauncherDashboardSetupToken() (string, error)

NewLauncherDashboardSetupToken creates the one-time token that lets the person who started Compa set the first dashboard password. Only the launcher's own browser launch and console show it.

func Recoverer

func Recoverer(next http.Handler) http.Handler

Recoverer recovers from panics in downstream handlers and returns a 500 Internal Server Error response when nothing was sent yet.

http.ErrAbortHandler is not a crash: a reverse proxy raises it when the client goes away mid-copy, so it is re-panicked for net/http to handle quietly. A response whose headers already went out is left as it is; writing an error into it would only corrupt it.

func ReferrerPolicyNoReferrer

func ReferrerPolicyNoReferrer(next http.Handler) http.Handler

ReferrerPolicyNoReferrer sets Referrer-Policy: no-referrer on every response so sensitive paths and query parameters are not leaked via the Referer header.

func RequestScheme

func RequestScheme(r *http.Request) string

RequestScheme is the scheme the browser used: https behind TLS or a proxy that says so in X-Forwarded-Proto, else http.

func SameOriginGuard

func SameOriginGuard(next http.Handler) http.Handler

SameOriginGuard refuses API writes (POST, PUT, PATCH, DELETE) and the web chat WebSocket handshake when a browser sent them from another origin. The session cookie is SameSite=Lax, which browsers also send from any other localhost port, so the cookie alone does not show that the dashboard asked. A request with neither Origin nor Sec-Fetch-Site comes from no browser, such as curl holding the cookie, and passes: its cookie is the gate.

func SameOriginRequest

func SameOriginRequest(r *http.Request) bool

SameOriginRequest reports whether r may act: a browser request must come from the page origin r itself names (scheme://host), shown by Origin or, when a browser omits that, by Sec-Fetch-Site same-origin. A request with neither header comes from no browser and passes.

func SecurityHeaders

func SecurityHeaders(cfg SecurityHeadersConfig, next http.Handler) http.Handler

SecurityHeaders sets the content security policy, nosniff, framing and referrer policies on every response, and keeps API answers out of caches. A handler serving other content (a downloaded file) replaces the CSP.

func SetLauncherDashboardSessionCookie

func SetLauncherDashboardSessionCookie(
	w http.ResponseWriter,
	r *http.Request,
	sessionValue string,
	secure func(*http.Request) bool,
)

SetLauncherDashboardSessionCookie writes the HttpOnly session cookie after successful dashboard password login.

Types

type ClientIPResolver

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

ClientIPResolver tells the address of the client behind a request the way IPAllowlist does: the peer, or, when the peer is a trusted proxy, the rightmost X-Forwarded-For address that is not one.

func NewClientIPResolver

func NewClientIPResolver(trustedProxyCIDRs []string) (*ClientIPResolver, error)

NewClientIPResolver returns a resolver trusting the proxies in trustedProxyCIDRs.

func (*ClientIPResolver) ClientIP

func (c *ClientIPResolver) ClientIP(r *http.Request) string

ClientIP returns the client address of r. A peer address that does not parse is returned as given.

type HostAllowlistConfig

type HostAllowlistConfig struct {
	// ListenHosts are the hosts the launcher was told to listen on (-host or
	// COMPA_LAUNCHER_HOST). Wildcards add nothing.
	ListenHosts []string
	// AllowedHosts are extra names, such as a reverse proxy's
	// (launcher-config allowed_hosts).
	AllowedHosts []string
	// LocalAddrs returns this computer's addresses. Nil reads the interfaces.
	LocalAddrs func() []net.IP
}

HostAllowlistConfig lists the Host names the dashboard answers to besides the ones it always accepts: loopback names, this computer's addresses and its host name.

type IPAllowlistConfig

type IPAllowlistConfig struct {
	AllowedCIDRs         []string
	AllowLocalhostBypass bool
	TrustedProxyCIDRs    []string
}

IPAllowlistConfig controls launcher network access decisions.

type LauncherDashboardAuthConfig

type LauncherDashboardAuthConfig struct {
	// Session is the session browsers must hold. When nil, ExpectedCookie is
	// the fixed session token.
	Session        *LauncherDashboardSession
	ExpectedCookie string
	// LocalAutoLogin enables one-shot startup auto-login.
	LocalAutoLogin *LauncherDashboardLocalAutoLogin
	// SecureCookie sets the session cookie's Secure flag. If nil, DefaultLauncherDashboardSecureCookie is used.
	SecureCookie func(*http.Request) bool
}

LauncherDashboardAuthConfig holds runtime material for dashboard access checks.

type LauncherDashboardLocalAutoLogin

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

LauncherDashboardLocalAutoLogin is an in-memory, one-shot startup grant. It is not a reusable credential; it only lets the launcher-opened browser receive the current process session cookie.

func NewLauncherDashboardLocalAutoLogin

func NewLauncherDashboardLocalAutoLogin(ttl time.Duration) (*LauncherDashboardLocalAutoLogin, error)

NewLauncherDashboardLocalAutoLogin creates a one-shot local auto-login grant.

func (*LauncherDashboardLocalAutoLogin) Renew

Renew replaces the grant with a fresh one-shot nonce valid for ttl and returns its URL path, so each browser the launcher opens gets its own link and an earlier, used one never comes back.

func (*LauncherDashboardLocalAutoLogin) URLPath

URLPath returns the one-shot local auto-login URL path including its nonce.

type LauncherDashboardSession

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

LauncherDashboardSession holds the session token every signed-in browser carries in its cookie. Rotating it signs every browser out at once.

func FixedLauncherDashboardSession

func FixedLauncherDashboardSession(token string) *LauncherDashboardSession

FixedLauncherDashboardSession returns a session holding token, for callers that pass a fixed cookie value.

func NewLauncherDashboardSession

func NewLauncherDashboardSession() (*LauncherDashboardSession, error)

NewLauncherDashboardSession creates a session with a fresh random token.

func (*LauncherDashboardSession) Rotate

func (s *LauncherDashboardSession) Rotate() (string, error)

Rotate replaces the session token, so every cookie issued before stops working, and returns the new one.

func (*LauncherDashboardSession) Token

func (s *LauncherDashboardSession) Token() string

Token returns the current session token.

func (*LauncherDashboardSession) Valid

func (s *LauncherDashboardSession) Valid(value string) bool

Valid reports whether value is the current session token.

type SecurityHeadersConfig

type SecurityHeadersConfig struct {
	// ScriptHashes are the CSP sources ('sha256-...') of the inline scripts
	// the dashboard page carries. Empty uses DashboardThemeScriptHash.
	ScriptHashes []string
}

SecurityHeadersConfig configures SecurityHeaders.

Jump to

Keyboard shortcuts

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