package config import ( "os" "strconv" "github.com/hashicorp/go-multierror" "github.com/homemade/scl" "github.com/pkg/errors" ) // Config holds the final server configuration. type Config struct { Server *Server `hcl:"server"` Github *Github `hcl:"github"` SSH *SSH `hcl:"ssh"` } // Server holds the configuration specific to the web server and sessions. type Server struct { Addr string `hcl:"address"` Port int `hcl:"port"` User string `hcl:"user"` CookieSecret string `hcl:"cookie_secret"` SecureCookie bool `hcl:"secure_cookie"` CSRFSecret string `hcl:"csrf_secret"` HTTPLogFile string `hcl:"http_logfile"` } // Auth holds the configuration specific to the OAuth provider. type Github struct { OauthClientID string `hcl:"oauth_client_id"` OauthClientSecret string `hcl:"oauth_client_secret"` OauthCallbackURL string `hcl:"oauth_callback_url"` UsersWhitelist []string `hcl:"users_whitelist"` OrgsWhitelist []string `hcl:"orgs_whitelist"` } // SSH holds the configuration specific to signing ssh keys. type SSH struct { SigningKey string `hcl:"signing_key"` AdditionalPrincipals []string `hcl:"additional_principals"` MaxAge string `hcl:"max_age"` Permissions []string `hcl:"permissions"` } func verifyConfig(c *Config) error { var err error if c.SSH == nil { err = multierror.Append(err, errors.New("missing ssh config section")) } if c.Github == nil { err = multierror.Append(err, errors.New("missing github config section")) } if c.Server == nil { err = multierror.Append(err, errors.New("missing server config section")) } return err } func setFromEnvironment(c *Config) { port, err := strconv.Atoi(os.Getenv("PORT")) if err == nil { c.Server.Port = port } if os.Getenv("OAUTH_CLIENT_ID") != "" { c.Github.OauthClientID = os.Getenv("OAUTH_CLIENT_ID") } if os.Getenv("OAUTH_CLIENT_SECRET") != "" { c.Github.OauthClientSecret = os.Getenv("OAUTH_CLIENT_SECRET") } if os.Getenv("CSRF_SECRET") != "" { c.Server.CSRFSecret = os.Getenv("CSRF_SECRET") } if os.Getenv("COOKIE_SECRET") != "" { c.Server.CookieSecret = os.Getenv("COOKIE_SECRET") } } // ReadConfig parses a hcl configuration file into a Config struct. func ReadConfig(f string) (*Config, error) { config := &Config{} if err := scl.DecodeFile(config, f); err != nil { return nil, errors.Wrapf(err, "unable to load config from file %s", f) } setFromEnvironment(config) if err := verifyConfig(config); err != nil { return nil, errors.Wrap(err, "unable to verify config") } return config, nil }