1
0
Эх сурвалжийг харах

CORS: add support for more parameters

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 3 жил өмнө
parent
commit
fdc10aa6c7

+ 6 - 0
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`.

+ 2 - 2
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

+ 4 - 4
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=

+ 5 - 3
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)
 	}

+ 26 - 14
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)

+ 10 - 7
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

+ 9 - 6
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)
 	}

+ 9 - 7
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)
 	}

+ 10 - 7
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

+ 8 - 2
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": "",