diff --git a/cuhttp/server.go b/cuhttp/server.go index c315f6f75..83aaac2b3 100644 --- a/cuhttp/server.go +++ b/cuhttp/server.go @@ -140,6 +140,7 @@ type ServiceDeps struct { DealMarket *storage_market.CurioStorageDealMarket } +// This starts the public-facing server for market calls. func StartHTTPServer(ctx context.Context, d *deps.Deps, sd *ServiceDeps) error { cfg := d.Cfg.HTTP @@ -152,11 +153,7 @@ func StartHTTPServer(ctx context.Context, d *deps.Deps, sd *ServiceDeps) error { chiRouter.Use(middleware.Recoverer) chiRouter.Use(handlers.ProxyHeaders) // Handle reverse proxy headers like X-Forwarded-For chiRouter.Use(secureHeaders(cfg.CSP)) - chiRouter.Use(corsHeaders) - - if cfg.EnableCORS { - chiRouter.Use(handlers.CORS(handlers.AllowedOrigins([]string{"https://" + cfg.DomainName}))) - } + chiRouter.Use(corsHeaders) // allows market calls from other domains // Set up the compression middleware with custom compression levels compressionMw, err := compressionMiddleware(&cfg.CompressionLevels) diff --git a/deps/config/doc_gen.go b/deps/config/doc_gen.go index b1583813b..cfbb794ca 100644 --- a/deps/config/doc_gen.go +++ b/deps/config/doc_gen.go @@ -902,10 +902,12 @@ Time duration string (e.g., "1h2m3s") in TOML format. (Default: "5m0s")`, Time duration string (e.g., "1h2m3s") in TOML format. (Default: "5m0s")`, }, { - Name: "EnableCORS", - Type: "bool", + Name: "CORSOrigins", + Type: "[]string", - Comment: `EnableCORS indicates whether Cross-Origin Resource Sharing (CORS) is enabled or not.`, + Comment: `CORSOrigins specifies the allowed origins for CORS requests. If empty, CORS is disabled. +If not empty, only the specified origins will be allowed for CORS requests. +This is required for third-party UI servers.`, }, { Name: "CSP", diff --git a/deps/config/types.go b/deps/config/types.go index 89dfb9888..f77e2a4a3 100644 --- a/deps/config/types.go +++ b/deps/config/types.go @@ -131,7 +131,7 @@ func DefaultCurioConfig() *CurioConfig { ReadTimeout: time.Second * 10, IdleTimeout: time.Hour, ReadHeaderTimeout: time.Second * 5, - EnableCORS: true, + CORSOrigins: []string{}, CSP: "inline", CompressionLevels: CompressionConfig{ GzipLevel: 6, @@ -862,8 +862,10 @@ type HTTPConfig struct { // Time duration string (e.g., "1h2m3s") in TOML format. (Default: "5m0s") ReadHeaderTimeout time.Duration - // EnableCORS indicates whether Cross-Origin Resource Sharing (CORS) is enabled or not. - EnableCORS bool + // CORSOrigins specifies the allowed origins for CORS requests. If empty, CORS is disabled. + // If not empty, only the specified origins will be allowed for CORS requests. + // This is required for third-party UI servers. + CORSOrigins []string // CSP sets the Content Security Policy for content served via the /piece/ retrieval endpoint. // Valid values: "off", "self", "inline" (Default: "inline") diff --git a/documentation/en/configuration/default-curio-configuration.md b/documentation/en/configuration/default-curio-configuration.md index e6235a4d1..935d4210b 100644 --- a/documentation/en/configuration/default-curio-configuration.md +++ b/documentation/en/configuration/default-curio-configuration.md @@ -558,10 +558,12 @@ description: The default curio configuration # type: time.Duration #ReadHeaderTimeout = "5s" - # EnableCORS indicates whether Cross-Origin Resource Sharing (CORS) is enabled or not. + # CORSOrigins specifies the allowed origins for CORS requests. If empty, CORS is disabled. + # If not empty, only the specified origins will be allowed for CORS requests. + # This is required for third-party UI servers. # - # type: bool - #EnableCORS = true + # type: []string + #CORSOrigins = [] # CSP sets the Content Security Policy for content served via the /piece/ retrieval endpoint. # Valid values: "off", "self", "inline" (Default: "inline") diff --git a/documentation/en/curio-market/curio-http-server.md b/documentation/en/curio-market/curio-http-server.md index da6f98905..95a037160 100644 --- a/documentation/en/curio-market/curio-http-server.md +++ b/documentation/en/curio-market/curio-http-server.md @@ -114,8 +114,8 @@ The Curio HTTP Server can be customized using the `HTTPConfig` structure, which Default: `2 minutes` — Prevents resources from being consumed by idle connections. If your application expects longer periods of inactivity, such as in long polling or WebSocket connections, this value should be adjusted accordingly. * **ReadHeaderTimeout**: The time allowed to read the request headers from the client.\ Default: `5 seconds` — Prevents slow clients from keeping connections open without sending complete headers. For standard web traffic, this value is sufficient, but it may need adjustment for certain client environments. -* **EnableCORS**: A boolean flag to enable or disable Cross-Origin Resource Sharing (CORS).\ - Default: `true` — This allows cross-origin requests, which is important for web applications that might make API calls from different domains. +* **CORSOrigins**: Specifies the allowed origins for CORS requests. If empty, CORS is disabled.\ + Default: `[]` (empty array) — This disables CORS by default for security. To enable CORS, specify the allowed origins (e.g., `["https://example.com", "https://app.example.com"]`). This is required for third-party UI servers. * **CompressionLevels**: Defines the compression levels for GZIP, Brotli, and Deflate, which are used to optimize the response size. The defaults balance performance and bandwidth savings: * **GzipLevel**: Default: `6` — A moderate compression level that balances speed and compression ratio, suitable for general-purpose use. * **BrotliLevel**: Default: `4` — A moderate Brotli compression level, which provides better compression than GZIP but is more CPU-intensive. This level is good for text-heavy responses like HTML or JSON. diff --git a/web/srv.go b/web/srv.go index 92d99ae48..df1fa21e4 100644 --- a/web/srv.go +++ b/web/srv.go @@ -17,6 +17,7 @@ import ( "strings" "time" + "github.com/gorilla/handlers" "github.com/gorilla/mux" "github.com/gorilla/websocket" logging "github.com/ipfs/go-log/v2" @@ -41,7 +42,11 @@ var webDev = os.Getenv("CURIO_WEB_DEV") == "1" func GetSrv(ctx context.Context, deps *deps.Deps, devMode bool) (*http.Server, error) { mx := mux.NewRouter() - mx.Use(corsMiddleware) + + // Add CORS middleware if origins are configured + if len(deps.Cfg.HTTP.CORSOrigins) > 0 { + mx.Use(handlers.CORS(handlers.AllowedOrigins(deps.Cfg.HTTP.CORSOrigins))) + } if !devMode { api.Routes(mx.PathPrefix("/api").Subrouter(), deps, webDev) @@ -278,19 +283,3 @@ func proxyCopy(dst, src *websocket.Conn, errc chan<- error, direction string) { } } } - -func corsMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") - w.Header().Set("Access-Control-Allow-Credentials", "true") - - if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) - return - } - - next.ServeHTTP(w, r) - }) -}