diff --git a/docs/full-configuration.md b/docs/full-configuration.md index 4fb26a99..6ddacfb2 100644 --- a/docs/full-configuration.md +++ b/docs/full-configuration.md @@ -194,6 +194,9 @@ The configuration file contains the following sections: - `exposed_headers`, list of strings. - `allow_credentials` boolean. - `max_age`, integer. + - `options_passthrough`, boolean. + - `options_success_status`, integer. + - `allow_private_network`, boolean. - `cache` struct containing cache configuration for the authenticated users. - `enabled`, boolean, set to true to enable user caching. Default: true. - `expiration_time`, integer. Expiration time, in minutes, for the cached users. 0 means unlimited. Default: 0. @@ -326,6 +329,9 @@ The configuration file contains the following sections: - `exposed_headers`, list of strings. - `allow_credentials` boolean. - `max_age`, integer. + - `options_passthrough`, boolean. + - `options_success_status`, integer. + - `allow_private_network`, boolean. - `setup` struct containing configurations for the initial setup screen - `installation_code`, string. If set, this installation code will be required when creating the first admin account. Please note that even if set using an environment variable this field is read at SFTPGo startup and not at runtime. This is not a license key or similar, the purpose here is to prevent anyone who can access to the initial setup screen from creating an admin user. Default: blank. - `installation_code_hint`, string. Description for the installation code input field. Default: `Installation code`. diff --git a/go.mod b/go.mod index c7153423..f2880856 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/pquerna/otp v1.3.0 github.com/prometheus/client_golang v1.12.2 github.com/robfig/cron/v3 v3.0.1 - github.com/rs/cors v1.8.2 + github.com/rs/cors v1.8.3-0.20220619195839-da52b0701de5 github.com/rs/xid v1.4.0 github.com/rs/zerolog v1.27.0 github.com/sftpgo/sdk v0.1.2-0.20220727164210-06723ba7ce9a @@ -155,7 +155,7 @@ require ( golang.org/x/tools v0.1.12 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f // indirect + google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 // indirect google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.66.6 // indirect diff --git a/go.sum b/go.sum index bef061b5..b2c6fa84 100644 --- a/go.sum +++ b/go.sum @@ -696,8 +696,8 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= -github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.8.3-0.20220619195839-da52b0701de5 h1:7PcjxKTsfGXpTMiTNNa1VllbsYSZJN5nhvVEWQMdX8Y= +github.com/rs/cors v1.8.3-0.20220619195839-da52b0701de5/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= @@ -1225,8 +1225,8 @@ google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f h1:XVHpVMvPs4MtH3h6cThzKs2snNexcfd35vQx2T3IuIY= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 h1:QntLWYqZeuBtJkth3m/6DLznnI0AHJr+AgJXvVh/izw= +google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= diff --git a/internal/common/eventmanager.go b/internal/common/eventmanager.go index c766f415..6e3aec41 100644 --- a/internal/common/eventmanager.go +++ b/internal/common/eventmanager.go @@ -747,6 +747,11 @@ func (j *eventCronJob) Run() { ticker := time.NewTicker(updateInterval) done := make(chan bool) + defer func() { + done <- true + ticker.Stop() + }() + go func(taskName string) { eventManagerLog(logger.LevelDebug, "update task %q timestamp worker started", taskName) for { @@ -762,9 +767,6 @@ func (j *eventCronJob) Run() { }(task.Name) executeRuleAsyncActions(rule, EventParams{}, nil) - - done <- true - ticker.Stop() } else { executeRuleAsyncActions(rule, EventParams{}, nil) } diff --git a/internal/config/config.go b/internal/config/config.go index a4710fa1..bee2500a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -285,13 +285,16 @@ func Init() { CACertificates: []string{}, CARevocationLists: []string{}, Cors: webdavd.CorsConfig{ - Enabled: false, - AllowedOrigins: []string{}, - AllowedMethods: []string{}, - AllowedHeaders: []string{}, - ExposedHeaders: []string{}, - AllowCredentials: false, - MaxAge: 0, + Enabled: false, + AllowedOrigins: []string{}, + AllowedMethods: []string{}, + AllowedHeaders: []string{}, + ExposedHeaders: []string{}, + AllowCredentials: false, + MaxAge: 0, + OptionsPassthrough: false, + OptionsSuccessStatus: 0, + AllowPrivateNetwork: false, }, Cache: webdavd.Cache{ Users: webdavd.UsersCacheConfig{ @@ -373,13 +376,16 @@ func Init() { TokenValidation: 0, MaxUploadFileSize: 1048576000, Cors: httpd.CorsConfig{ - Enabled: false, - AllowedOrigins: []string{}, - AllowedMethods: []string{}, - AllowedHeaders: []string{}, - ExposedHeaders: []string{}, - AllowCredentials: false, - MaxAge: 0, + Enabled: false, + AllowedOrigins: []string{}, + AllowedMethods: []string{}, + AllowedHeaders: []string{}, + ExposedHeaders: []string{}, + AllowCredentials: false, + MaxAge: 0, + OptionsPassthrough: false, + OptionsSuccessStatus: 0, + AllowPrivateNetwork: false, }, Setup: httpd.SetupConfig{ InstallationCode: "", @@ -1899,6 +1905,9 @@ func setViperDefaults() { 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.options_passthrough", globalConf.WebDAVD.Cors.OptionsPassthrough) + viper.SetDefault("webdavd.cors.options_success_status", globalConf.WebDAVD.Cors.OptionsSuccessStatus) + viper.SetDefault("webdavd.cors.allow_private_network", globalConf.WebDAVD.Cors.AllowPrivateNetwork) viper.SetDefault("webdavd.cors.max_age", globalConf.WebDAVD.Cors.MaxAge) viper.SetDefault("webdavd.cache.users.expiration_time", globalConf.WebDAVD.Cache.Users.ExpirationTime) viper.SetDefault("webdavd.cache.users.max_size", globalConf.WebDAVD.Cache.Users.MaxSize) @@ -1961,6 +1970,9 @@ func setViperDefaults() { viper.SetDefault("httpd.cors.exposed_headers", globalConf.HTTPDConfig.Cors.ExposedHeaders) viper.SetDefault("httpd.cors.allow_credentials", globalConf.HTTPDConfig.Cors.AllowCredentials) viper.SetDefault("httpd.cors.max_age", globalConf.HTTPDConfig.Cors.MaxAge) + viper.SetDefault("httpd.cors.options_passthrough", globalConf.HTTPDConfig.Cors.OptionsPassthrough) + viper.SetDefault("httpd.cors.options_success_status", globalConf.HTTPDConfig.Cors.OptionsSuccessStatus) + viper.SetDefault("httpd.cors.allow_private_network", globalConf.HTTPDConfig.Cors.AllowPrivateNetwork) viper.SetDefault("httpd.setup.installation_code", globalConf.HTTPDConfig.Setup.InstallationCode) viper.SetDefault("httpd.setup.installation_code_hint", globalConf.HTTPDConfig.Setup.InstallationCodeHint) viper.SetDefault("httpd.hide_support_link", globalConf.HTTPDConfig.HideSupportLink) diff --git a/internal/httpd/httpd.go b/internal/httpd/httpd.go index 6ea2e738..fc2509d3 100644 --- a/internal/httpd/httpd.go +++ b/internal/httpd/httpd.go @@ -639,13 +639,16 @@ type SetupConfig struct { // CorsConfig defines the CORS configuration type CorsConfig struct { - AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` - AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"` - AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` - ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"` - AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"` - Enabled bool `json:"enabled" mapstructure:"enabled"` - MaxAge int `json:"max_age" mapstructure:"max_age"` + AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` + AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"` + AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` + ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"` + AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"` + Enabled bool `json:"enabled" mapstructure:"enabled"` + MaxAge int `json:"max_age" mapstructure:"max_age"` + OptionsPassthrough bool `json:"options_passthrough" mapstructure:"options_passthrough"` + OptionsSuccessStatus int `json:"options_success_status" mapstructure:"options_success_status"` + AllowPrivateNetwork bool `json:"allow_private_network" mapstructure:"allow_private_network"` } // Conf httpd daemon configuration diff --git a/internal/httpd/server.go b/internal/httpd/server.go index 3e6a941a..b06aa619 100644 --- a/internal/httpd/server.go +++ b/internal/httpd/server.go @@ -1138,12 +1138,15 @@ func (s *httpdServer) initializeRouter() { } if s.cors.Enabled { c := cors.New(cors.Options{ - AllowedOrigins: util.RemoveDuplicates(s.cors.AllowedOrigins, true), - AllowedMethods: util.RemoveDuplicates(s.cors.AllowedMethods, true), - AllowedHeaders: util.RemoveDuplicates(s.cors.AllowedHeaders, true), - ExposedHeaders: util.RemoveDuplicates(s.cors.ExposedHeaders, true), - MaxAge: s.cors.MaxAge, - AllowCredentials: s.cors.AllowCredentials, + AllowedOrigins: util.RemoveDuplicates(s.cors.AllowedOrigins, true), + AllowedMethods: util.RemoveDuplicates(s.cors.AllowedMethods, true), + AllowedHeaders: util.RemoveDuplicates(s.cors.AllowedHeaders, true), + ExposedHeaders: util.RemoveDuplicates(s.cors.ExposedHeaders, true), + MaxAge: s.cors.MaxAge, + AllowCredentials: s.cors.AllowCredentials, + OptionsPassthrough: s.cors.OptionsPassthrough, + OptionsSuccessStatus: s.cors.OptionsSuccessStatus, + AllowPrivateNetwork: s.cors.AllowPrivateNetwork, }) s.router.Use(c.Handler) } diff --git a/internal/webdavd/server.go b/internal/webdavd/server.go index 2eca057f..7e933a70 100644 --- a/internal/webdavd/server.go +++ b/internal/webdavd/server.go @@ -57,13 +57,15 @@ func (s *webDavServer) listenAndServe(compressor *middleware.Compressor) error { } if s.config.Cors.Enabled { c := cors.New(cors.Options{ - AllowedOrigins: util.RemoveDuplicates(s.config.Cors.AllowedOrigins, true), - AllowedMethods: util.RemoveDuplicates(s.config.Cors.AllowedMethods, true), - AllowedHeaders: util.RemoveDuplicates(s.config.Cors.AllowedHeaders, true), - ExposedHeaders: util.RemoveDuplicates(s.config.Cors.ExposedHeaders, true), - MaxAge: s.config.Cors.MaxAge, - AllowCredentials: s.config.Cors.AllowCredentials, - OptionsPassthrough: true, + AllowedOrigins: util.RemoveDuplicates(s.config.Cors.AllowedOrigins, true), + AllowedMethods: util.RemoveDuplicates(s.config.Cors.AllowedMethods, true), + AllowedHeaders: util.RemoveDuplicates(s.config.Cors.AllowedHeaders, true), + ExposedHeaders: util.RemoveDuplicates(s.config.Cors.ExposedHeaders, true), + MaxAge: s.config.Cors.MaxAge, + AllowCredentials: s.config.Cors.AllowCredentials, + OptionsPassthrough: s.config.Cors.OptionsPassthrough, + OptionsSuccessStatus: s.config.Cors.OptionsSuccessStatus, + AllowPrivateNetwork: s.config.Cors.AllowPrivateNetwork, }) handler = c.Handler(handler) } diff --git a/internal/webdavd/webdavd.go b/internal/webdavd/webdavd.go index c4a4d809..a0c054f7 100644 --- a/internal/webdavd/webdavd.go +++ b/internal/webdavd/webdavd.go @@ -52,13 +52,16 @@ type ServiceStatus struct { // CorsConfig defines the CORS configuration type CorsConfig struct { - AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` - AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"` - AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` - ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"` - AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"` - Enabled bool `json:"enabled" mapstructure:"enabled"` - MaxAge int `json:"max_age" mapstructure:"max_age"` + AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` + AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"` + AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` + ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"` + AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"` + Enabled bool `json:"enabled" mapstructure:"enabled"` + MaxAge int `json:"max_age" mapstructure:"max_age"` + OptionsPassthrough bool `json:"options_passthrough" mapstructure:"options_passthrough"` + OptionsSuccessStatus int `json:"options_success_status" mapstructure:"options_success_status"` + AllowPrivateNetwork bool `json:"allow_private_network" mapstructure:"allow_private_network"` } // UsersCacheConfig defines the cache configuration for users diff --git a/sftpgo.json b/sftpgo.json index a78e7fbf..a8560ede 100644 --- a/sftpgo.json +++ b/sftpgo.json @@ -165,7 +165,10 @@ "allowed_headers": [], "exposed_headers": [], "allow_credentials": false, - "max_age": 0 + "max_age": 0, + "options_passthrough": false, + "options_success_status": 0, + "allow_private_network": false }, "cache": { "users": { @@ -330,7 +333,10 @@ "allowed_headers": [], "exposed_headers": [], "allow_credentials": false, - "max_age": 0 + "max_age": 0, + "options_passthrough": false, + "options_success_status": 0, + "allow_private_network": false }, "setup": { "installation_code": "",