package config import ( "io" "os" "reflect" "time" "github.com/pkg/errors" "github.com/caarlos0/env/v10" "gopkg.in/yaml.v2" ) type Config struct { Debug bool `yaml:"debug" env:"DEBUG"` HTTP HTTPConfig `yaml:"http" envPrefix:"HTTP_"` Hydra HydraConfig `yaml:"hydra" envPrefix:"HYDRA_"` Session SessionConfig `yaml:"session" envPrefix:"SESSION_"` Sentry SentryConfig `yaml:"sentry" envPrefix:"SENTRY_"` WebAuthn WebAuthnConfig `yaml:"webauthn" envPrefix:"WEBAUTHN_"` API APIConfig `yaml:"api" envPrefix:"API_"` Storage StorageConfig `yaml:"storage" envPrefix:"STORAGE_"` } // NewFromFile retrieves the configuration from the given file func NewFromFile(filepath string) (*Config, error) { config := NewDefault() data, err := os.ReadFile(filepath) if err != nil { return nil, errors.Wrapf(err, "could not read file '%s'", filepath) } if err := yaml.Unmarshal(data, config); err != nil { return nil, errors.Wrapf(err, "could not unmarshal configuration") } return config, nil } type HydraConfig struct { BaseURL string `yaml:"baseURL" env:"BASE_URL"` // Fake upstream SSL termination adding the "X-Forwarded-Proto: https" to the OIDC client // HTTP request headers. // Required by ory/hydra in some networks topologies FakeSSLTermination bool `yaml:"fakeSSLTermination" env:"FAKE_SSL_TERMINATION"` HTTPClientTimeout time.Duration `yaml:"httpClientTimeout" env:"HTTP_CLIENT_TIMEOUT"` } type SessionConfig struct { DefaultDuration int `yaml:"defaultDuration" env:"DEFAULT_DURATION"` RememberMeDuration int `yaml:"rememberMeDuration" env:"REMEMBER_ME_DURATION"` } type SentryConfig struct { DSN string `yaml:"dsn" env:"DSN"` // Server events sampling rate, see https://docs.sentry.io/platforms/go/configuration/options/ ServerSampleRate float64 `yaml:"serverSampleRate" env:"SERVER_SAMPLE_RATE"` ServerFlushTimeout time.Duration `yaml:"serverFlushTimeout" env:"SERVER_FLUSH_TIMEOUT"` Environment string `yaml:"environment" env:"ENVIRONMENT"` } func NewDumpDefault() *Config { config := NewDefault() return config } func NewDefault() *Config { return &Config{ Debug: false, HTTP: HTTPConfig{ Address: ":3000", CookieAuthenticationKey: "", CookieEncryptionKey: "", TokenEncryptionKey: "", TokenSigningKey: "", CookieMaxAge: int((time.Hour * 1).Seconds()), // 1 hour TemplateDir: "template", PublicDir: "public", BaseURL: "/", }, Hydra: HydraConfig{ BaseURL: "http://localhost:4445/", FakeSSLTermination: false, HTTPClientTimeout: time.Second * 30, //nolint: gomnb }, Session: SessionConfig{ DefaultDuration: int((time.Hour * 1).Seconds()), // 1 hour RememberMeDuration: int((time.Hour * 24 * 30).Seconds()), // 30 days }, Sentry: SentryConfig{ DSN: "", ServerSampleRate: 1, ServerFlushTimeout: 2 * time.Second, Environment: "", }, WebAuthn: NewDefaultWebAuthnConfig(), API: NewDefaultAPIConfig(), Storage: NewDefaultStorageConfig(), } } func Dump(config *Config, w io.Writer) error { data, err := yaml.Marshal(config) if err != nil { return errors.Wrap(err, "could not dump config") } if _, err := w.Write(data); err != nil { return err } return nil } func WithEnvironment(conf *Config) error { if err := env.ParseWithOptions(conf, env.Options{ Prefix: "HYDRA_WEBAUTHN_", FuncMap: map[reflect.Type]env.ParserFunc{ reflect.TypeOf(Accounts{}): parseAccounts, }, }); err != nil { return err } return nil }