Explorar o código

config: manually set viper defaults

so we can override config via env var even without a configuration file

Fixes #208
Nicola Murino %!s(int64=4) %!d(string=hai) anos
pai
achega
ebb18fa57d
Modificáronse 4 ficheiros con 116 adicións e 9 borrados
  1. 91 4
      config/config.go
  2. 24 2
      config/config_test.go
  3. 1 1
      docs/account.md
  4. 0 2
      docs/full-configuration.md

+ 91 - 4
config/config.go

@@ -165,6 +165,7 @@ func init() {
 	replacer := strings.NewReplacer(".", "__")
 	viper.SetEnvKeyReplacer(replacer)
 	viper.SetConfigName(DefaultConfigName)
+	setViperDefaults()
 	viper.AutomaticEnv()
 	viper.AllowEmptyEnv(true)
 }
@@ -252,10 +253,8 @@ func LoadConfig(configDir, configName string) error {
 	viper.AddConfigPath(".")
 	viper.SetConfigName(configName)
 	if err = viper.ReadInConfig(); err != nil {
-		logger.Warn(logSender, "", "error loading configuration file: %v. Default configuration will be used: %+v",
-			err, getRedactedGlobalConf())
-		logger.WarnToConsole("error loading configuration file: %v. Default configuration will be used.", err)
-		return err
+		logger.Warn(logSender, "", "error loading configuration file: %v", err)
+		logger.WarnToConsole("error loading configuration file: %v", err)
 	}
 	err = viper.Unmarshal(&globalConf)
 	if err != nil {
@@ -349,3 +348,91 @@ func checkCommonParamsCompatibility() {
 		globalConf.Common.ProxyAllowed = globalConf.SFTPD.ProxyAllowed   //nolint:staticcheck
 	}
 }
+
+func setViperDefaults() {
+	viper.SetDefault("common.idle_timeout", globalConf.Common.IdleTimeout)
+	viper.SetDefault("common.upload_mode", globalConf.Common.UploadMode)
+	viper.SetDefault("common.actions.execute_on", globalConf.Common.Actions.ExecuteOn)
+	viper.SetDefault("common.actions.hook", globalConf.Common.Actions.Hook)
+	viper.SetDefault("common.setstat_mode", globalConf.Common.SetstatMode)
+	viper.SetDefault("common.proxy_protocol", globalConf.Common.ProxyProtocol)
+	viper.SetDefault("common.proxy_allowed", globalConf.Common.ProxyAllowed)
+	viper.SetDefault("common.post_connect_hook", globalConf.Common.PostConnectHook)
+	viper.SetDefault("sftpd.bind_port", globalConf.SFTPD.BindPort)
+	viper.SetDefault("sftpd.bind_address", globalConf.SFTPD.BindAddress)
+	viper.SetDefault("sftpd.max_auth_tries", globalConf.SFTPD.MaxAuthTries)
+	viper.SetDefault("sftpd.banner", globalConf.SFTPD.Banner)
+	viper.SetDefault("sftpd.host_keys", globalConf.SFTPD.HostKeys)
+	viper.SetDefault("sftpd.kex_algorithms", globalConf.SFTPD.KexAlgorithms)
+	viper.SetDefault("sftpd.ciphers", globalConf.SFTPD.Ciphers)
+	viper.SetDefault("sftpd.macs", globalConf.SFTPD.MACs)
+	viper.SetDefault("sftpd.trusted_user_ca_keys", globalConf.SFTPD.TrustedUserCAKeys)
+	viper.SetDefault("sftpd.login_banner_file", globalConf.SFTPD.LoginBannerFile)
+	viper.SetDefault("sftpd.enabled_ssh_commands", globalConf.SFTPD.EnabledSSHCommands)
+	viper.SetDefault("sftpd.keyboard_interactive_auth_hook", globalConf.SFTPD.KeyboardInteractiveHook)
+	viper.SetDefault("sftpd.password_authentication", globalConf.SFTPD.PasswordAuthentication)
+	viper.SetDefault("ftpd.bind_port", globalConf.FTPD.BindPort)
+	viper.SetDefault("ftpd.bind_address", globalConf.FTPD.BindAddress)
+	viper.SetDefault("ftpd.banner", globalConf.FTPD.Banner)
+	viper.SetDefault("ftpd.banner_file", globalConf.FTPD.BannerFile)
+	viper.SetDefault("ftpd.active_transfers_port_non_20", globalConf.FTPD.ActiveTransfersPortNon20)
+	viper.SetDefault("ftpd.force_passive_ip", globalConf.FTPD.ForcePassiveIP)
+	viper.SetDefault("ftpd.passive_port_range.start", globalConf.FTPD.PassivePortRange.Start)
+	viper.SetDefault("ftpd.passive_port_range.end", globalConf.FTPD.PassivePortRange.End)
+	viper.SetDefault("ftpd.certificate_file", globalConf.FTPD.CertificateFile)
+	viper.SetDefault("ftpd.certificate_key_file", globalConf.FTPD.CertificateKeyFile)
+	viper.SetDefault("ftpd.tls_mode", globalConf.FTPD.TLSMode)
+	viper.SetDefault("webdavd.bind_port", globalConf.WebDAVD.BindPort)
+	viper.SetDefault("webdavd.bind_address", globalConf.WebDAVD.BindAddress)
+	viper.SetDefault("webdavd.certificate_file", globalConf.WebDAVD.CertificateFile)
+	viper.SetDefault("webdavd.certificate_key_file", globalConf.WebDAVD.CertificateKeyFile)
+	viper.SetDefault("webdavd.cors.enabled", globalConf.WebDAVD.Cors.Enabled)
+	viper.SetDefault("webdavd.cors.allowed_origins", globalConf.WebDAVD.Cors.AllowedOrigins)
+	viper.SetDefault("webdavd.cors.allowed_methods", globalConf.WebDAVD.Cors.AllowedMethods)
+	viper.SetDefault("webdavd.cors.allowed_headers", globalConf.WebDAVD.Cors.AllowedHeaders)
+	viper.SetDefault("webdavd.cors.exposed_headers", globalConf.WebDAVD.Cors.ExposedHeaders)
+	viper.SetDefault("webdavd.cors.allow_credentials", globalConf.WebDAVD.Cors.AllowCredentials)
+	viper.SetDefault("webdavd.cors.max_age", globalConf.WebDAVD.Cors.MaxAge)
+	viper.SetDefault("webdavd.cache.enabled", globalConf.WebDAVD.Cache.Enabled)
+	viper.SetDefault("webdavd.cache.expiration_time", globalConf.WebDAVD.Cache.ExpirationTime)
+	viper.SetDefault("webdavd.cache.max_size", globalConf.WebDAVD.Cache.MaxSize)
+	viper.SetDefault("data_provider.driver", globalConf.ProviderConf.Driver)
+	viper.SetDefault("data_provider.name", globalConf.ProviderConf.Name)
+	viper.SetDefault("data_provider.host", globalConf.ProviderConf.Host)
+	viper.SetDefault("data_provider.port", globalConf.ProviderConf.Port)
+	viper.SetDefault("data_provider.username", globalConf.ProviderConf.Username)
+	viper.SetDefault("data_provider.password", globalConf.ProviderConf.Password)
+	viper.SetDefault("data_provider.sslmode", globalConf.ProviderConf.SSLMode)
+	viper.SetDefault("data_provider.connection_string", globalConf.ProviderConf.ConnectionString)
+	viper.SetDefault("data_provider.sql_tables_prefix", globalConf.ProviderConf.SQLTablesPrefix)
+	viper.SetDefault("data_provider.manage_users", globalConf.ProviderConf.ManageUsers)
+	viper.SetDefault("data_provider.track_quota", globalConf.ProviderConf.TrackQuota)
+	viper.SetDefault("data_provider.pool_size", globalConf.ProviderConf.PoolSize)
+	viper.SetDefault("data_provider.users_base_dir", globalConf.ProviderConf.UsersBaseDir)
+	viper.SetDefault("data_provider.actions.execute_on", globalConf.ProviderConf.Actions.ExecuteOn)
+	viper.SetDefault("data_provider.actions.hook", globalConf.ProviderConf.Actions.Hook)
+	viper.SetDefault("data_provider.external_auth_hook", globalConf.ProviderConf.ExternalAuthHook)
+	viper.SetDefault("data_provider.external_auth_scope", globalConf.ProviderConf.ExternalAuthScope)
+	viper.SetDefault("data_provider.credentials_path", globalConf.ProviderConf.CredentialsPath)
+	viper.SetDefault("data_provider.prefer_database_credentials", globalConf.ProviderConf.PreferDatabaseCredentials)
+	viper.SetDefault("data_provider.pre_login_hook", globalConf.ProviderConf.PreLoginHook)
+	viper.SetDefault("data_provider.post_login_hook", globalConf.ProviderConf.PostLoginHook)
+	viper.SetDefault("data_provider.post_login_scope", globalConf.ProviderConf.PostLoginScope)
+	viper.SetDefault("data_provider.check_password_hook", globalConf.ProviderConf.CheckPasswordHook)
+	viper.SetDefault("data_provider.check_password_scope", globalConf.ProviderConf.CheckPasswordScope)
+	viper.SetDefault("data_provider.password_hashing.argon2_options.memory", globalConf.ProviderConf.PasswordHashing.Argon2Options.Memory)
+	viper.SetDefault("data_provider.password_hashing.argon2_options.iterations", globalConf.ProviderConf.PasswordHashing.Argon2Options.Iterations)
+	viper.SetDefault("data_provider.password_hashing.argon2_options.parallelism", globalConf.ProviderConf.PasswordHashing.Argon2Options.Parallelism)
+	viper.SetDefault("data_provider.update_mode", globalConf.ProviderConf.UpdateMode)
+	viper.SetDefault("httpd.bind_port", globalConf.HTTPDConfig.BindPort)
+	viper.SetDefault("httpd.bind_address", globalConf.HTTPDConfig.BindAddress)
+	viper.SetDefault("httpd.templates_path", globalConf.HTTPDConfig.TemplatesPath)
+	viper.SetDefault("httpd.static_files_path", globalConf.HTTPDConfig.StaticFilesPath)
+	viper.SetDefault("httpd.backups_path", globalConf.HTTPDConfig.BackupsPath)
+	viper.SetDefault("httpd.auth_user_file", globalConf.HTTPDConfig.AuthUserFile)
+	viper.SetDefault("httpd.certificate_file", globalConf.HTTPDConfig.CertificateFile)
+	viper.SetDefault("httpd.certificate_key_file", globalConf.HTTPDConfig.CertificateKeyFile)
+	viper.SetDefault("http.timeout", globalConf.HTTPConfig.Timeout)
+	viper.SetDefault("http.ca_certificates", globalConf.HTTPConfig.CACertificates)
+	viper.SetDefault("http.skip_tls_verify", globalConf.HTTPConfig.SkipTLSVerify)
+}

+ 24 - 2
config/config_test.go

@@ -36,11 +36,11 @@ func TestLoadConfigTest(t *testing.T) {
 	confName := tempConfigName + ".json"
 	configFilePath := filepath.Join(configDir, confName)
 	err = config.LoadConfig(configDir, tempConfigName)
-	assert.NotNil(t, err)
+	assert.NoError(t, err)
 	err = ioutil.WriteFile(configFilePath, []byte("{invalid json}"), os.ModePerm)
 	assert.NoError(t, err)
 	err = config.LoadConfig(configDir, tempConfigName)
-	assert.NotNil(t, err)
+	assert.NoError(t, err)
 	err = ioutil.WriteFile(configFilePath, []byte("{\"sftpd\": {\"bind_port\": \"a\"}}"), os.ModePerm)
 	assert.NoError(t, err)
 	err = config.LoadConfig(configDir, tempConfigName)
@@ -280,3 +280,25 @@ func TestSetGetConfig(t *testing.T) {
 	assert.Equal(t, webDavConf.CertificateFile, config.GetWebDAVDConfig().CertificateFile)
 	assert.Equal(t, webDavConf.CertificateKeyFile, config.GetWebDAVDConfig().CertificateKeyFile)
 }
+
+func TestConfigFromEnv(t *testing.T) {
+	os.Setenv("SFTPGO_SFTPD__BIND_ADDRESS", "127.0.0.1")
+	os.Setenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS", "41")
+	os.Setenv("SFTPGO_DATA_PROVIDER__POOL_SIZE", "10")
+	os.Setenv("SFTPGO_DATA_PROVIDER__ACTIONS__EXECUTE_ON", "add")
+	t.Cleanup(func() {
+		os.Unsetenv("SFTPGO_SFTPD__BIND_ADDRESS")
+		os.Unsetenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS")
+		os.Unsetenv("SFTPGO_DATA_PROVIDER__POOL_SIZE")
+		os.Unsetenv("SFTPGO_DATA_PROVIDER__ACTIONS__EXECUTE_ON")
+	})
+	err := config.LoadConfig(".", "invalid config")
+	assert.NoError(t, err)
+	sftpdConfig := config.GetSFTPDConfig()
+	assert.Equal(t, "127.0.0.1", sftpdConfig.BindAddress)
+	dataProviderConf := config.GetProviderConf()
+	assert.Equal(t, uint32(41), dataProviderConf.PasswordHashing.Argon2Options.Iterations)
+	assert.Equal(t, 10, dataProviderConf.PoolSize)
+	assert.Len(t, dataProviderConf.Actions.ExecuteOn, 1)
+	assert.Contains(t, dataProviderConf.Actions.ExecuteOn, "add")
+}

+ 1 - 1
docs/account.md

@@ -45,7 +45,7 @@ For each account, the following properties can be configured:
   - `allowed_extensions`, list of, case insensitive, allowed files extension. Shell like expansion is not supported so you have to specify `.jpg` and not `*.jpg`. Any file that does not end with this suffix will be denied
   - `denied_extensions`, list of, case insensitive, denied files extension. Denied file extensions are evaluated before the allowed ones
   - `path`, SFTP/SCP path, if no other specific filter is defined, the filter apply for sub directories too. For example if filters are defined for the paths `/` and `/sub` then the filters for `/` are applied for any file outside the `/sub` directory
-- `fs_provider`, filesystem to serve via SFTP. Local filesystem, S3 Compatible Object Storage, Google Cloud Storage and Azure Blob Storage are supported
+- `fs_provider`, filesystem to serve via SFTP. Local filesystem (0), S3 Compatible Object Storage (1), Google Cloud Storage (2) and Azure Blob Storage (3) are supported
 - `s3_bucket`, required for S3 filesystem
 - `s3_region`, required for S3 filesystem. Must match the region for your bucket. You can find here the list of available [AWS regions](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions). For example if your bucket is at `Frankfurt` you have to set the region to `eu-central-1`
 - `s3_access_key`

+ 0 - 2
docs/full-configuration.md

@@ -200,5 +200,3 @@ Let's see some examples:
 
 - To set sftpd `bind_port`, you need to define the env var `SFTPGO_SFTPD__BIND_PORT`
 - To set the `execute_on` actions, you need to define the env var `SFTPGO_COMMON__ACTIONS__EXECUTE_ON`. For example `SFTPGO_COMMON__ACTIONS__EXECUTE_ON=upload,download`
-
-Please note that in order to override configuration options with environment variables, you need a configuration file containing the options to override, this is a [viper bug](https://github.com/spf13/viper/issues/584). For example, you can deploy the default configuration file and then override the options to customize using environment variables.