package config import ( "encoding/json" "errors" "fmt" "io/fs" "os" "github.com/dexidp/dex/connector/oidc" "github.com/dexidp/dex/storage" "github.com/sirupsen/logrus" ) type envVar string const ( varLogLevel envVar = "LOG_LEVEL" varServerMode envVar = "SERVER_MODE" varServerHost envVar = "SERVER_HOST" varServerPort envVar = "SERVER_PORT" varServerSocket envVar = "SERVER_SOCK_PATH" varIssuer envVar = "ISSUER" varStorageType envVar = "STORAGE_TYPE" varStorageFile envVar = "STORAGE_FILEPATH" varStorageHost envVar = "STORAGE_HOST" varStoragePort envVar = "STORAGE_PORT" varStorageDB envVar = "STORAGE_DB" varStorageUser envVar = "STORAGE_USER" varStoragePassword envVar = "STORAGE_PASSWORD" varStorageSSLMode envVar = "STORAGE_SSL_MODE" varStorageSSLCaFile envVar = "STORAGE_SSL_CA_FILE" ) type ListeningMode string const ( ModeUnix ListeningMode = "unix" ModeNet ListeningMode = "net" ) type BackendConfigType string const ( Memory BackendConfigType = "memory" SQLite BackendConfigType = "sqlite" ) const ( defaultLogLevel = logrus.InfoLevel defaultServerMode = ModeNet defaultServerHost = "0.0.0.0" defaultServerPort = 5000 defaultServerSocket = "" defaultIssuer = "http://locahost:5000" defaultStorageType = Memory defaultStorageFile = "./polyculeconnect.db" defaultStorageHost = "127.0.0.1" defaultStoragePort = 5432 defaultStorageDB = "polyculeconnect" defaultStorageUser = "polyculeconnect" defaultStoragePassword = "polyculeconnect" defaultStorageSSLMode = "disable" defaultStorageSSLCaFile = "" ) // Deprecated: remove when we finally drop the JSON config type BackendConfig struct { Config *oidc.Config `json:"config"` Name string `json:"name"` ID string `json:"ID"` Type BackendConfigType `json:"type"` Local bool `json:"local"` } // Deprecated: remove when we finally drop the JSON config type OpenConnectConfig struct { ClientConfigs []*storage.Client `json:"clients"` BackendConfigs []*BackendConfig `json:"backends"` Issuer string `json:"issuer"` } type StorageConfig struct { File string Host string Port int Database string User string Password string Ssl struct { Mode string CaFile string } } type jsonConf struct { OpenConnectConfig *OpenConnectConfig `json:"openconnect"` } type AppConfig struct { LogLevel logrus.Level ServerMode ListeningMode Host string Port int SockPath string StorageType string StorageConfig *StorageConfig OpenConnectConfig *OpenConnectConfig } func parseLevel(lvlStr string) logrus.Level { for _, lvl := range logrus.AllLevels { if lvl.String() == lvlStr { return lvl } } return logrus.InfoLevel } func (ac *AppConfig) UnmarshalJSON(data []byte) error { var jsonConf jsonConf if err := json.Unmarshal(data, &jsonConf); err != nil { return fmt.Errorf("failed to read JSON: %w", err) } ac.OpenConnectConfig = jsonConf.OpenConnectConfig if ac.OpenConnectConfig == nil { ac.OpenConnectConfig = &OpenConnectConfig{} } return nil } func (ac *AppConfig) getConfFromEnv() { ac.LogLevel = parseLevel(getStringFromEnv(varLogLevel, defaultLogLevel.String())) ac.ServerMode = ListeningMode(getStringFromEnv(varServerMode, string(defaultServerMode))) ac.Host = getStringFromEnv(varServerHost, defaultServerHost) ac.Port = getIntFromEnv(varServerPort, defaultServerPort) ac.SockPath = getStringFromEnv(varServerSocket, defaultServerSocket) ac.StorageType = getStringFromEnv(varStorageType, string(defaultStorageType)) ac.StorageConfig.Database = getStringFromEnv(varStorageDB, defaultStorageDB) ac.StorageConfig.File = getStringFromEnv(varStorageFile, defaultStorageFile) ac.StorageConfig.Host = getStringFromEnv(varStorageHost, defaultStorageHost) ac.StorageConfig.Port = getIntFromEnv(varStoragePort, defaultStoragePort) ac.StorageConfig.User = getStringFromEnv(varStorageUser, defaultStorageUser) ac.StorageConfig.Password = getStringFromEnv(varStoragePassword, defaultStoragePassword) ac.StorageConfig.Ssl.CaFile = getStringFromEnv(varStorageSSLCaFile, defaultStorageSSLCaFile) ac.StorageConfig.Ssl.Mode = getStringFromEnv(varStorageSSLMode, defaultStorageSSLMode) ac.OpenConnectConfig.Issuer = getStringFromEnv(varIssuer, defaultIssuer) } func (ac *AppConfig) RedirectURI() string { return ac.OpenConnectConfig.Issuer + "/callback" } func New(filepath string) (*AppConfig, error) { var conf AppConfig conf.StorageConfig = &StorageConfig{} conf.OpenConnectConfig = &OpenConnectConfig{} content, err := os.ReadFile(filepath) if err != nil { if !errors.Is(err, fs.ErrNotExist) { return nil, fmt.Errorf("failed to read config file %q: %w", filepath, err) } } else { if err := json.Unmarshal(content, &conf); err != nil { return nil, fmt.Errorf("failed to parse config file: %w", err) } } conf.getConfFromEnv() return &conf, nil }