package config import ( "fmt" "os" "strings" ) type Config struct { // Database DatabaseURL string // Server PublicAddr string AdminAddr string BaseURL string // Sessions SessionSecret string // Forgejo ForgejoURL string ForgejoAPIToken string // Postmark PostmarkServerToken string PostmarkFromEmail string // OAuth - Google GoogleClientID string GoogleClientSecret string // OAuth - Microsoft MicrosoftClientID string MicrosoftClientSecret string MicrosoftTenantID string // OAuth - Apple AppleClientID string AppleTeamID string AppleKeyID string AppleKeyPath string // Admin TailscaleAllowedUsers []string } func Load() (*Config, error) { cfg := &Config{ DatabaseURL: getEnv("DATABASE_URL", ""), PublicAddr: getEnv("PUBLIC_ADDR", ":8080"), AdminAddr: getEnv("ADMIN_ADDR", ":8081"), BaseURL: getEnv("BASE_URL", "http://localhost:8080"), SessionSecret: getEnv("SESSION_SECRET", ""), ForgejoURL: getEnv("FORGEJO_URL", ""), ForgejoAPIToken: getEnv("FORGEJO_API_TOKEN", ""), PostmarkServerToken: getEnv("POSTMARK_SERVER_TOKEN", ""), PostmarkFromEmail: getEnv("POSTMARK_FROM_EMAIL", ""), GoogleClientID: getEnv("GOOGLE_CLIENT_ID", ""), GoogleClientSecret: getEnv("GOOGLE_CLIENT_SECRET", ""), MicrosoftClientID: getEnv("MICROSOFT_CLIENT_ID", ""), MicrosoftClientSecret: getEnv("MICROSOFT_CLIENT_SECRET", ""), MicrosoftTenantID: getEnv("MICROSOFT_TENANT_ID", "common"), AppleClientID: getEnv("APPLE_CLIENT_ID", ""), AppleTeamID: getEnv("APPLE_TEAM_ID", ""), AppleKeyID: getEnv("APPLE_KEY_ID", ""), AppleKeyPath: getEnv("APPLE_KEY_PATH", ""), } if allowed := getEnv("TAILSCALE_ALLOWED_USERS", ""); allowed != "" { cfg.TailscaleAllowedUsers = strings.Split(allowed, ",") for i := range cfg.TailscaleAllowedUsers { cfg.TailscaleAllowedUsers[i] = strings.TrimSpace(cfg.TailscaleAllowedUsers[i]) } } if cfg.DatabaseURL == "" { return nil, fmt.Errorf("DATABASE_URL is required") } if len(cfg.SessionSecret) < 32 { return nil, fmt.Errorf("SESSION_SECRET must be at least 32 characters") } return cfg, nil } func getEnv(key, fallback string) string { if val := os.Getenv(key); val != "" { return val } return fallback }