package config import ( "fmt" "net/url" "strings" ) // ValidateConfig validates a loaded Config and returns a list of human-readable // error messages. An empty slice means the config is valid. // Called at startup — the server must exit 1 if any errors are returned. func ValidateConfig(cfg *Config) []string { var errs []string // Issuer must be a valid URL with an http(s) scheme. if cfg.Issuer == "" { errs = append(errs, "issuer: must not be empty") } else { u, err := url.Parse(cfg.Issuer) if err != nil || u.Scheme == "" || u.Host == "" { errs = append(errs, fmt.Sprintf("issuer: %q is not a valid URL (must include scheme and host)", cfg.Issuer)) } else if u.Scheme != "http" && u.Scheme != "https" { errs = append(errs, fmt.Sprintf("issuer: scheme must be http or https, got %q", u.Scheme)) } } // Port must be in the valid TCP range. if cfg.Port < 1 || cfg.Port > 65535 { errs = append(errs, fmt.Sprintf("port: must be between 1 and 65535, got %d", cfg.Port)) } // At least one client must be registered. if len(cfg.Clients) == 0 { errs = append(errs, "clients: at least one client must be defined") } // Each client must have at least one redirect URI and a non-empty clientId. for i, c := range cfg.Clients { prefix := fmt.Sprintf("clients[%d] (%s)", i, c.ClientID) if c.ClientID == "" { prefix = fmt.Sprintf("clients[%d]", i) errs = append(errs, prefix+": clientId must not be empty") } if len(c.RedirectURIs) == 0 { errs = append(errs, prefix+": redirect_uri: at least one redirectUri must be registered") } // Warn about wildcard redirect URIs (they are blocked at runtime anyway). for _, uri := range c.RedirectURIs { if strings.ContainsAny(uri, "*?") { errs = append(errs, prefix+fmt.Sprintf(": redirect_uri %q must not contain wildcards", uri)) } } } // Private key PEM path must be provided (existence is checked at startup). if cfg.PrivateKeyPEM == "" { errs = append(errs, "privateKeyPem: path must not be empty") } return errs }