appview

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: May 9, 2026 License: MIT Imports: 52 Imported by: 0

Documentation

Overview

Package appview implements the ATCR AppView component, which serves as the main OCI Distribution API server. It resolves identities (handle/DID to PDS endpoint), routes manifests to user's PDS, routes blobs to hold services, validates OAuth tokens, and issues registry JWTs. This package provides Viper-based configuration with YAML file support, environment variable overrides, and HTTP server setup for the AppView service.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssetHash

func AssetHash(path string) string

AssetHash returns the cache-busting hash for an asset path

func CacheMiddleware

func CacheMiddleware(h http.Handler, maxAge int) http.Handler

CacheMiddleware adds Cache-Control headers to static file responses

func ComputeAssetHashes

func ComputeAssetHashes(overrides *BrandingOverrides)

ComputeAssetHashes recomputes cache-busting hashes using the overlay FS. Call this before serving requests if using BrandingOverrides.

func DIDFromBaseURL

func DIDFromBaseURL(baseURL string) string

DIDFromBaseURL derives a did:web identifier from a base URL. Per the did:web spec, non-standard ports are percent-encoded. Examples:

"https://atcr.io" → "did:web:atcr.io"
"http://localhost:5000" → "did:web:localhost%3A5000"

func DomainRoutingMiddleware

func DomainRoutingMiddleware(registryDomains []string, uiBaseURL string) func(http.Handler) http.Handler

DomainRoutingMiddleware enforces three-tier domain routing:

  1. UI domain (BaseURL hostname): serves web UI, auth, and static assets. Blocks /v2/* with an OCI UNSUPPORTED error — registry API lives on the dedicated registry domain(s).
  2. Registry domains: allows /v2/* for Docker clients. Redirects everything else to the UI domain with 307 Temporary Redirect.
  3. Unknown domains (CDN origins, IPs, etc.): redirects all requests to the UI domain with 307, except /health for load balancer probes.

func ExampleYAML

func ExampleYAML() ([]byte, error)

ExampleYAML returns a fully-commented YAML configuration with default values.

func PublicHandler

func PublicHandler(overrides *BrandingOverrides) http.Handler

PublicHandler returns HTTP handler for static files. Pass nil for default atcr.io behavior.

func PublicRootFiles

func PublicRootFiles(overrides *BrandingOverrides) ([]string, error)

PublicRootFiles returns list of root-level files in static directory (not subdirectories). Pass nil for default atcr.io behavior.

func PublicSubdir

func PublicSubdir(name string, overrides *BrandingOverrides) http.Handler

PublicSubdir returns an http.Handler for a subdirectory within public/. Pass nil for default atcr.io behavior.

func RegisterTheme

func RegisterTheme(name string, fn func() *BrandingOverrides)

RegisterTheme registers a named theme. Call from init() in theme packages.

func Templates

func Templates(overrides *BrandingOverrides) (*template.Template, error)

Templates returns parsed templates with helper functions. Pass nil for default atcr.io behavior.

Types

type AIConfig

type AIConfig struct {
	// Anthropic API key for the AI Image Advisor feature.
	APIKey string `yaml:"api_key" comment:"Anthropic API key for AI Image Advisor. Also reads CLAUDE_API_KEY env var as fallback."`
}

AIConfig defines AI-powered image advisor settings

type AppViewServer

type AppViewServer struct {
	// Router is the chi router. Add routes before calling Serve().
	Router chi.Router

	// Config is the AppView configuration.
	Config *Config

	// Database is the read-write SQLite database.
	Database *sql.DB

	// ReadOnlyDB is the read-only SQLite database connection.
	ReadOnlyDB *sql.DB

	// SessionStore manages web UI sessions.
	SessionStore *db.SessionStore

	// DeviceStore manages device authorization flows.
	DeviceStore *db.DeviceStore

	// OAuthStore manages OAuth session persistence.
	OAuthStore *db.OAuthStore

	// OAuthServer handles OAuth authorization and callback endpoints.
	OAuthServer *oauth.Server

	// OAuthClientApp is the indigo OAuth client application.
	OAuthClientApp *indigooauth.ClientApp

	// Refresher manages OAuth session refresh and caching.
	Refresher *oauth.Refresher

	// Templates are the parsed HTML templates.
	Templates *template.Template

	// HealthChecker checks hold service health.
	HealthChecker *holdhealth.Checker

	// ReadmeFetcher fetches README content for repository pages.
	ReadmeFetcher *readme.Fetcher

	// TokenIssuer issues registry JWTs (nil if auth is not configured).
	TokenIssuer *token.Issuer

	// HoldAuthorizer checks hold access permissions.
	HoldAuthorizer auth.HoldAuthorizer

	// OAuthKey is the P-256 private key used for OAuth client auth and appview service identity.
	OAuthKey *atcrypto.PrivateKeyP256

	// BillingManager handles Stripe billing and tier updates (nil if billing disabled).
	BillingManager *billing.Manager

	// WebhookDispatcher dispatches scan webhooks (stored in appview DB).
	WebhookDispatcher *webhooks.Dispatcher
	// contains filtered or unexported fields
}

AppViewServer is the AppView service with an exposed router for extensibility. Consumers can add routes to Router and hooks before calling Serve().

func NewAppViewServer

func NewAppViewServer(cfg *Config, branding *BrandingOverrides) (*AppViewServer, error)

NewAppViewServer creates a fully-initialized AppView server ready for the consumer to add routes and hooks before calling Serve(). Pass nil for branding to use default atcr.io assets and templates.

func (*AppViewServer) AddOAuthPostAuthHook

func (s *AppViewServer) AddOAuthPostAuthHook(hook OAuthPostAuthHook)

AddOAuthPostAuthHook registers a hook that runs after the default OAuth post-auth logic. Multiple hooks run in registration order.

func (*AppViewServer) AddTokenPostAuthHook

func (s *AppViewServer) AddTokenPostAuthHook(hook TokenPostAuthHook)

AddTokenPostAuthHook registers a hook that runs after the default token post-auth logic. Multiple hooks run in registration order.

func (*AppViewServer) DID

func (s *AppViewServer) DID() string

DID returns the appview's did:web identity derived from its BaseURL.

func (*AppViewServer) Serve

func (s *AppViewServer) Serve() error

Serve starts the HTTP server and blocks until shutdown signal.

type AuthConfig

type AuthConfig struct {
	// X.509 certificate matching the JWT signing key.
	CertPath string `` /* 137-byte string literal not displayed */

	// TokenExpiration is the JWT expiration duration (5 minutes, not configurable)
	TokenExpiration time.Duration `yaml:"-"`

	// ServiceName is the service name used for JWT issuer and service fields.
	// Derived from base URL hostname (e.g., "atcr.io")
	ServiceName string `yaml:"-"`
}

AuthConfig defines authentication settings

type BrandingOverrides

type BrandingOverrides struct {
	// PublicFS overlays public/ assets (favicons, CSS, images, etc.).
	// Files in this FS take priority over the embedded defaults.
	PublicFS fs.FS

	// TemplatesFS overlays templates/ (nav-brand.html, hero.html, etc.).
	// Go's template.ParseFS replaces {{ define "name" }} blocks when
	// called twice with the same name, so consumer templates naturally
	// override defaults.
	TemplatesFS fs.FS

	// ExtraCSS is injected as a <style> block after the main stylesheet.
	// Useful for DaisyUI color variable overrides without build tooling.
	ExtraCSS string

	// ExtraFuncMap is merged into the template FuncMap.
	ExtraFuncMap template.FuncMap
}

BrandingOverrides allows consumers to customize the AppView's public assets, templates, CSS, and template functions. Pass nil for default atcr.io behavior.

func LookupTheme

func LookupTheme(name string) (*BrandingOverrides, error)

LookupTheme returns BrandingOverrides for a registered theme name. Returns nil for empty name (default branding). Returns an error for unknown theme names.

type Config

type Config struct {
	Version          string                       `yaml:"version" comment:"Configuration format version."`
	LogLevel         string                       `yaml:"log_level" comment:"Log level: debug, info, warn, error."`
	LogShipper       config.LogShipperConfig      `yaml:"log_shipper" comment:"Remote log shipping settings."`
	Server           ServerConfig                 `yaml:"server" comment:"HTTP server and identity settings."`
	UI               UIConfig                     `yaml:"ui" comment:"Web UI settings."`
	Health           HealthConfig                 `yaml:"health" comment:"Health check and cache settings."`
	Jetstream        JetstreamConfig              `yaml:"jetstream" comment:"ATProto Jetstream event stream settings."`
	Auth             AuthConfig                   `yaml:"auth" comment:"JWT authentication settings."`
	CredentialHelper CredentialHelperConfig       `yaml:"credential_helper" comment:"Credential helper download settings."`
	Legal            LegalConfig                  `yaml:"legal" comment:"Legal page customization for self-hosted instances."`
	AI               AIConfig                     `yaml:"ai" comment:"AI-powered image advisor settings."`
	Labeler          LabelerRefConfig             `yaml:"labeler" comment:"ATProto labeler for content moderation (DMCA takedowns)."`
	Billing          billing.Config               `yaml:"billing" comment:"Stripe billing integration (requires -tags billing build)."`
	Distribution     *configuration.Configuration `yaml:"-"` // Wrapped distribution config for compatibility
}

Config represents the AppView service configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config populated with all default values (no validation).

func LoadConfig

func LoadConfig(yamlPath string) (*Config, error)

LoadConfig builds a complete configuration using Viper layered loading: defaults -> YAML file -> environment variables. yamlPath is optional; empty string means env-only (backward compatible).

type CredentialHelperConfig

type CredentialHelperConfig struct {
	// TangledRepo is the Tangled repository URL for downloads
	TangledRepo string `yaml:"tangled_repo" comment:"Tangled repository URL for credential helper downloads."`
}

CredentialHelperConfig defines credential helper download settings

type HealthConfig

type HealthConfig struct {
	// How long to cache hold health check results.
	CacheTTL time.Duration `yaml:"cache_ttl" comment:"How long to cache hold health check results."`

	// How often to refresh hold health checks.
	CheckInterval time.Duration `yaml:"check_interval" comment:"How often to refresh hold health checks."`
}

HealthConfig defines health check and cache settings

type JetstreamConfig

type JetstreamConfig struct {
	// Jetstream WebSocket endpoints, tried in order on failure.
	URLs []string `yaml:"urls" comment:"Jetstream WebSocket endpoints, tried in order on failure."`

	// Sync existing records from PDS on startup.
	BackfillEnabled bool `yaml:"backfill_enabled" comment:"Sync existing records from PDS on startup."`

	// How often to re-run backfill to catch missed events. Set to 0 to only backfill on startup.
	BackfillInterval time.Duration `yaml:"backfill_interval" comment:"How often to re-run backfill to catch missed events. Set to 0 to only backfill on startup."`

	// Relay endpoints for backfill — MUST support com.atproto.sync.listReposByCollection. Tried in order on failure.
	RelayEndpoints []string `` /* 141-byte string literal not displayed */
}

JetstreamConfig defines ATProto Jetstream settings

type LabelerRefConfig added in v0.1.3

type LabelerRefConfig struct {
	// DID or URL of the labeler service for content moderation.
	DID string `yaml:"did" comment:"DID or URL of the ATProto labeler (e.g., did:web:labeler.atcr.io). Empty disables label filtering."`
}

LabelerRefConfig defines the connection to an ATProto labeler service.

type LegalConfig

type LegalConfig struct {
	// Organization name for legal pages. Defaults to ClientName.
	CompanyName string `yaml:"company_name" comment:"Organization name for Terms of Service and Privacy Policy. Defaults to server.client_name."`

	// Governing law jurisdiction for legal terms.
	Jurisdiction string `yaml:"jurisdiction" comment:"Governing law jurisdiction for legal terms."`
}

LegalConfig defines legal page customization for self-hosted instances

type OAuthPostAuthHook

type OAuthPostAuthHook func(ctx context.Context, did, handle, pdsEndpoint, sessionID string) error

OAuthPostAuthHook is called after the default OAuth post-auth logic (profile creation, avatar fetch, crew registration). Hooks added after NewAppViewServer but before the first request work correctly.

type ServerConfig

type ServerConfig struct {
	// Listen address for the HTTP server.
	Addr string `yaml:"addr" comment:"Listen address, e.g. \":5000\" or \"127.0.0.1:5000\"."`

	// Public-facing URL for OAuth callbacks and JWT realm.
	BaseURL string `yaml:"base_url" comment:"Public-facing URL for OAuth callbacks and JWT realm. Auto-detected if empty."`

	// DID of the default hold service for blob storage.
	DefaultHoldDID string `yaml:"default_hold_did" comment:"DID of the hold service for blob storage, e.g. \"did:web:hold01.atcr.io\" (REQUIRED)."`

	// Allows HTTP (not HTTPS) for DID resolution.
	TestMode bool `yaml:"test_mode" comment:"Allows HTTP (not HTTPS) for DID resolution and uses transition:generic OAuth scope."`

	// Display name shown on OAuth authorization screens.
	ClientName string `yaml:"client_name" comment:"Display name shown on OAuth authorization screens."`

	// Short name used in page titles and browser tabs.
	ClientShortName string `yaml:"client_short_name" comment:"Short name used in page titles and browser tabs."`

	// Separate domains for OCI registry API. First entry is the primary (used for JWT service name and UI display).
	RegistryDomains []string `` /* 147-byte string literal not displayed */

	// DIDs of holds this appview manages billing for.
	ManagedHolds []string `yaml:"managed_holds" comment:"DIDs of holds this appview manages billing for. Tier updates are pushed to these holds."`
}

ServerConfig defines server settings

type TokenPostAuthHook

type TokenPostAuthHook func(ctx context.Context, did, handle, pdsEndpoint, accessToken string) error

TokenPostAuthHook is called after the default token post-auth logic (profile creation). Hooks added after NewAppViewServer but before the first request work correctly.

type UIConfig

type UIConfig struct {
	// SQLite database path.
	DatabasePath string `yaml:"database_path" comment:"SQLite/libSQL database for OAuth sessions, stars, pull counts, and device approvals."`

	// Visual theme name (e.g. "seamark"). Empty string uses default atcr.io branding.
	Theme string `yaml:"theme" comment:"Visual theme name (e.g. \"seamark\"). Empty uses default atcr.io branding."`

	// libSQL sync URL for embedded replicas. Works with Turso cloud or self-hosted libsql-server.
	// Leave empty for local-only SQLite mode (selfhost/dev).
	LibsqlSyncURL string `` /* 152-byte string literal not displayed */

	// Auth token for libSQL sync. Required if LibsqlSyncURL is set.
	LibsqlAuthToken string `yaml:"libsql_auth_token" comment:"Auth token for libSQL sync. Required if libsql_sync_url is set."`

	// How often to sync with the remote libSQL server.
	LibsqlSyncInterval time.Duration `yaml:"libsql_sync_interval" comment:"How often to sync with remote libSQL server. Default: 60s."`

	// Source code URL displayed in the footer "Source" link.
	SourceURL string `yaml:"source_url" comment:"Source code URL displayed in the footer \"Source\" link. Defaults to the upstream ATCR project."`
}

UIConfig defines web UI settings

Directories

Path Synopsis
Package db provides the database layer for the AppView web UI, including SQLite schema initialization, migrations, and query functions for OAuth sessions, device flows, repository metadata, stars, pull counts, and user profiles.
Package db provides the database layer for the AppView web UI, including SQLite schema initialization, migrations, and query functions for OAuth sessions, device flows, repository metadata, stars, pull counts, and user profiles.
Package handlers provides HTTP handlers for the AppView web UI, including home page, repository browsing, search, user authentication, settings, device management, and API endpoints for the web interface.
Package handlers provides HTTP handlers for the AppView web UI, including home page, repository browsing, search, user authentication, settings, device management, and API endpoints for the web interface.
Package holdclient provides client functions for the appview to call hold XRPC endpoints.
Package holdclient provides client functions for the appview to call hold XRPC endpoints.
Package holdhealth provides health checking for hold service endpoints.
Package holdhealth provides health checking for hold service endpoints.
Package jetstream provides an ATProto Jetstream consumer for real-time updates.
Package jetstream provides an ATProto Jetstream consumer for real-time updates.
Package labeler provides a subscription client for consuming labels from an ATProto labeler service.
Package labeler provides a subscription client for consuming labels from an ATProto labeler service.
Package licenses provides SPDX license validation and parsing for container image annotations.
Package licenses provides SPDX license validation and parsing for container image annotations.
Package middleware provides HTTP middleware for AppView, including authentication (session-based for web UI, token-based for registry), identity resolution (handle/DID to PDS endpoint), and hold discovery for routing blobs to storage endpoints.
Package middleware provides HTTP middleware for AppView, including authentication (session-based for web UI, token-based for registry), identity resolution (handle/DID to PDS endpoint), and hold discovery for routing blobs to storage endpoints.
Package ogcard provides OpenGraph card image generation for ATCR.
Package ogcard provides OpenGraph card image generation for ATCR.
Package readme provides fetching and rendering of README files from Git hosting platforms.
Package readme provides fetching and rendering of README files from Git hosting platforms.
Package routes provides route registration for the AppView web UI and API endpoints.
Package routes provides route registration for the AppView web UI and API endpoints.
Package storage implements the storage routing layer for AppView.
Package storage implements the storage routing layer for AppView.
Package webhooks provides webhook dispatch and formatting for push and scan notifications.
Package webhooks provides webhook dispatch and formatting for push and scan notifications.

Jump to

Keyboard shortcuts

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