storefront

package
v0.14.0-rc0 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ProfileNamespace = "x402"
	ProfileConfigMap = "obol-storefront-profile"
	ProfileDataKey   = "profile.json"
	// DefaultLogoPath is the light-on-dark Obol wordmark; only legible on
	// the dark/obol themes.
	DefaultLogoPath = "/obol-stack-logo.png"
	// DefaultMarkPath is the dark square Obol mark used as the default
	// brand image on the light theme (paired with the display name as
	// text), where the wordmark would be invisible.
	DefaultMarkPath = "/obol-logo.png"
)
View Source
const (
	ThemeLight = "light"
	ThemeDark  = "dark"
	ThemeObol  = "obol"

	// DefaultTheme is what renders when the operator has not chosen.
	DefaultTheme = ThemeLight
)

Theme presets for every seller-facing HTML surface (public storefront, 402 paywall pages, SIWX sign-in, error pages, per-offer landing pages, Scalar API docs). The preset list is deliberately short and hardcoded; operators pick a name via `obol sell info set --theme` and may override the accent with a single hex value. Arbitrary palette editing is out of scope — full control is the bring-your-own-frontend path.

Variables

This section is empty.

Functions

func ConfigMapManifest

func ConfigMapManifest(p schemas.StorefrontProfile) (map[string]any, error)

ConfigMapManifest returns a kubectl-applyable ConfigMap for the profile.

func CustomCSSFromFile added in v0.13.0

func CustomCSSFromFile(path string) (string, error)

CustomCSSFromFile reads and validates a local stylesheet for `sell info set --css-file`.

func DescribeLogoURL

func DescribeLogoURL(raw string) string

DescribeLogoURL returns a terminal-friendly rendering of a logo URL: inline data: URIs are summarised (mime + decoded size) instead of dumping the base64 payload; everything else passes through unchanged.

func InlineImageFromFile added in v0.13.0

func InlineImageFromFile(path, what string) (string, error)

InlineImageFromFile reads a local image file and returns it as a data:image/...;base64 URI suitable for the profile's image fields. Inline images are self-contained — immune to CORS, hotlink protection, and dead hosts — but must fit the ConfigMap budget (maxInlineLogoBytes). what names the field in errors ("logo", "favicon", "OG image").

func InlineLogoFromFile

func InlineLogoFromFile(path string) (string, error)

InlineLogoFromFile is InlineImageFromFile for the logo field.

func IsDefaultLogoURL

func IsDefaultLogoURL(raw string) bool

IsDefaultLogoURL reports whether url is the stack default wordmark (relative or absolute).

func MarshalProfile

func MarshalProfile(p schemas.StorefrontProfile) (string, error)

MarshalProfile serialises a profile for ConfigMap storage.

func MergeProfile

func MergeProfile(base, patch schemas.StorefrontProfile) schemas.StorefrontProfile

MergeProfile overlays non-empty patch fields onto base.

func ParseProfile

func ParseProfile(raw string) (*schemas.StorefrontProfile, error)

ParseProfile decodes profile JSON from a ConfigMap data key.

func ProfileLocalPath

func ProfileLocalPath(cfg *config.Config) string

ProfileLocalPath is the host-side record of the operator profile.

func ReconcileRecorded

func ReconcileRecorded(cfg *config.Config, u *ui.UI)

ReconcileRecorded re-applies the operator's recorded storefront branding into the cluster during `obol stack up`.

`obol sell info set` writes the profile to both the x402/obol-storefront-profile ConfigMap (etcd, destroyed by `obol stack down`) and a host-side record at $CONFIG_DIR/storefront/profile.json (survives cluster recreation). Without this replay a fresh `stack up` would come back with the branding on disk but no matching ConfigMap, so the controller would publish the default catalog envelope.

The host file is the source of truth. No record on disk => nothing to do. Best-effort: a failure warns but never blocks stack-up.

func RenderRichText added in v0.13.0

func RenderRichText(markdown string) template.HTML

RenderRichText is the ONLY markdown→HTML path for operator-authored copy (storefront/offer descriptions). Everything it emits is served on public, tunnel-exposed pages, so the pipeline is deliberately strict:

  1. goldmark renders a CommonMark subset with raw HTML DISABLED — anything HTML-shaped in the source is escaped/omitted, never passed through. Single newlines become <br> (operators write plain paragraphs and expect line breaks to survive).
  2. Headings are demoted into the h3/h4 band so seller copy can't impersonate page chrome.
  3. bluemonday sanitizes the rendered HTML against a tight allow-list: p, br, strong, em, ul, ol, li, code, pre, a, h3, h4. Links keep href only for https:/mailto: targets and are forced rel="nofollow".

Renderers must insert the result as template.HTML (Go) or via dangerouslySetInnerHTML (React) — this function is the trust boundary; do not add a second markdown or sanitize path elsewhere.

func ResolvePublished

func ResolvePublished(explicit *schemas.StorefrontProfile, baseURL string) schemas.StorefrontProfile

ResolvePublished merges an operator-set profile over stack defaults.

func SafeAssetURL added in v0.13.0

func SafeAssetURL(raw string) template.URL

SafeAssetURL marks a profile asset URL as safe for html/template URL contexts. The template engine's URL sanitizer rejects data: URIs outright (renders #ZgotmplZ), but inline data:image/...;base64 logos/favicons are a supported profile form (`sell info set --logo-file`) — validated at set time AND re-checked here before the bypass. Everything else must be plain http(s); unexpected shapes collapse to "".

func SafeCustomCSS added in v0.13.0

func SafeCustomCSS(css string) string

SafeCustomCSS is the render-time guard: it re-runs the validation and returns "" when the stored value would break out of a <style> element. Renderers must use this (never the raw profile field) when inlining.

func ThemeNames added in v0.13.0

func ThemeNames() []string

ThemeNames lists the valid preset names, default first.

func ValidateAccentColor added in v0.13.0

func ValidateAccentColor(accent string) error

ValidateAccentColor accepts empty (= preset accent) or a #hex color.

func ValidateContactEmail

func ValidateContactEmail(raw string) error

ValidateContactEmail accepts a bare operator contact address for OpenAPI info.contact.email (required by x402scan discovery audits).

func ValidateCustomCSS added in v0.13.0

func ValidateCustomCSS(css string) error

ValidateCustomCSS enforces the injection contract for operator CSS: it is inlined verbatim inside a <style> element on public pages, so the ONLY hard security requirement is that it cannot close that element (or open a comment/CDATA escape) and start emitting markup. Everything else is the operator styling their own storefront.

func ValidateImageURL added in v0.13.0

func ValidateImageURL(raw, what string) error

ValidateImageURL accepts absolute http(s) URLs, site-relative paths, or inline data:image/...;base64 URIs (self-contained — immune to CORS, hotlink protection, and dead hosts). what names the field in errors ("logo", "favicon", "OG image").

func ValidateLogoURL

func ValidateLogoURL(raw string) error

ValidateLogoURL is ValidateImageURL for the logo field.

func ValidateThemeName added in v0.13.0

func ValidateThemeName(name string) error

ValidateThemeName accepts empty (= default) or one of the preset names.

Types

type LogoPreflight

type LogoPreflight struct {
	// LoadFailure is true when the image could not be fetched at all
	// (network error, HTTP error status, or a non-image response) — the
	// logo will be broken everywhere, not just for strict consumers.
	LoadFailure bool
	// Warnings are human-readable problems found by the probe.
	Warnings []string
}

LogoPreflight is the result of probing a logo URL the way a browser would load it.

func PreflightLogoURL

func PreflightLogoURL(ctx context.Context, rawURL string) LogoPreflight

PreflightLogoURL fetches an absolute logo URL and checks the properties browsers and catalog consumers depend on: reachability, an image content-type, permissive CORS (for fetch()/canvas-based consumers), https (mixed content on https storefront pages), and size. Problems come back as Warnings rather than an error so the caller can decide whether to proceed. Empty and data: URIs are self-contained and probe as OK.

func (LogoPreflight) OK

func (p LogoPreflight) OK() bool

OK reports whether the probe found no problems.

type Theme added in v0.13.0

type Theme struct {
	Name string
	Dark bool
	Vars map[string]string
}

Theme is a resolved preset: a name, a light/dark hint for browser UI (color-scheme, scrollbars), and the token→hex map shared by every surface.

func ResolveTheme added in v0.13.0

func ResolveTheme(name, accent string) Theme

ResolveTheme returns the preset for name with the optional accent override applied to the green tokens. Unknown or empty names fall back to DefaultTheme; invalid accents are ignored (validation happens at set time — render time never fails). The returned Vars map is a copy.

func (Theme) CSSVars added in v0.13.0

func (t Theme) CSSVars() string

CSSVars renders the token map as CSS custom-property declarations ("--bg01:#ffffff;--bg02:...;") in a fixed order, for direct inclusion inside a :root block. All values come from the hardcoded presets or an accent that already matched accentColorRe, so the output is CSS-safe by construction.

func (Theme) ThemeColor added in v0.13.0

func (t Theme) ThemeColor() string

ThemeColor is the browser-chrome color (<meta name="theme-color">).

Jump to

Keyboard shortcuts

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