package main import ( "fmt" "os" "strconv" "strings" "time" ) // Config holds all runtime settings, sourced from environment variables so the // server is easy to run under systemd, Docker or a PaaS without code changes. type Config struct { ListenAddr string // e.g. ":8080" PublicURL string // externally reachable base URL, e.g. https://tmdb.example.com TMDBKey string // the single shared TMDB v3 API key TMDBBase string // upstream base, defaults to https://api.themoviedb.org/3 Issuer string // Authentik OIDC issuer URL ClientID string // OAuth2 client id ClientSecret string // OAuth2 client secret RedirectURL string // OAuth2 redirect URL (PublicURL + /callback if empty) SessionKey []byte // HMAC secret for signing access tokens / state cookies AllowGroups []string // if set, the user must be in one of these Authentik groups TokenTTL time.Duration // lifetime of issued desktop-app tokens DatabaseURL string // PostgreSQL DSN for library sync; empty disables sync } func getenv(key, def string) string { if v := strings.TrimSpace(os.Getenv(key)); v != "" { return v } return def } func loadConfig() (*Config, error) { c := &Config{ ListenAddr: getenv("LISTEN_ADDR", ":8080"), PublicURL: strings.TrimRight(getenv("PUBLIC_URL", "http://localhost:8080"), "/"), TMDBKey: getenv("TMDB_API_KEY", ""), TMDBBase: strings.TrimRight(getenv("TMDB_BASE_URL", "https://api.themoviedb.org/3"), "/"), Issuer: getenv("OIDC_ISSUER", ""), ClientID: getenv("OIDC_CLIENT_ID", ""), ClientSecret: getenv("OIDC_CLIENT_SECRET", ""), RedirectURL: getenv("OIDC_REDIRECT_URL", ""), DatabaseURL: getenv("DATABASE_URL", ""), } if c.RedirectURL == "" { c.RedirectURL = c.PublicURL + "/callback" } secret := getenv("SESSION_SECRET", "") if secret == "" { return nil, fmt.Errorf("SESSION_SECRET is required (a long random string)") } c.SessionKey = []byte(secret) if groups := getenv("ALLOWED_GROUPS", ""); groups != "" { for _, g := range strings.Split(groups, ",") { if g = strings.TrimSpace(g); g != "" { c.AllowGroups = append(c.AllowGroups, g) } } } days, err := strconv.Atoi(getenv("TOKEN_TTL_DAYS", "90")) if err != nil || days <= 0 { days = 90 } c.TokenTTL = time.Duration(days) * 24 * time.Hour // Required fields. var missing []string if c.TMDBKey == "" { missing = append(missing, "TMDB_API_KEY") } if c.Issuer == "" { missing = append(missing, "OIDC_ISSUER") } if c.ClientID == "" { missing = append(missing, "OIDC_CLIENT_ID") } if c.ClientSecret == "" { missing = append(missing, "OIDC_CLIENT_SECRET") } if len(missing) > 0 { return nil, fmt.Errorf("missing required environment variables: %s", strings.Join(missing, ", ")) } return c, nil }