From bb7ee24087efdf9910a07c8ca480bcd9ba4a422f Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Wed, 19 Jan 2022 09:27:13 -0700 Subject: [PATCH] router: support the `Access-Control-Request-Private-Network` header (#117) --- config/config.go | 6 ++++++ router/middleware/middleware.go | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index e01bf73..052abdb 100644 --- a/config/config.go +++ b/config/config.go @@ -286,6 +286,12 @@ type Configuration struct { // The Panel URL is automatically allowed, this is only needed for adding // additional origins. AllowedOrigins []string `json:"allowed_origins" yaml:"allowed_origins"` + + // AllowCORSPrivateNetwork sets the `Access-Control-Request-Private-Network` header which + // allows client browsers to make requests to internal IP addresses over HTTP. This setting + // is only required by users running Wings without SSL certificates and using internal IP + // addresses in order to connect. Most users should NOT enable this setting. + AllowCORSPrivateNetwork bool `json:"allow_cors_private_network" yaml:"allow_cors_private_network"` } // NewAtPath creates a new struct and set the path where it should be stored. diff --git a/router/middleware/middleware.go b/router/middleware/middleware.go index 88f9851..d102174 100644 --- a/router/middleware/middleware.go +++ b/router/middleware/middleware.go @@ -218,19 +218,29 @@ func CaptureErrors() gin.HandlerFunc { // SetAccessControlHeaders sets the access request control headers on all of // the requests. func SetAccessControlHeaders() gin.HandlerFunc { - origins := config.Get().AllowedOrigins - location := config.Get().PanelLocation + cfg := config.Get() + origins := cfg.AllowedOrigins + location := cfg.PanelLocation + allowPrivateNetwork := cfg.AllowCORSPrivateNetwork return func(c *gin.Context) { + c.Header("Access-Control-Allow-Origin", location) c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS") + c.Header("Access-Control-Allow-Headers", "Accept, Accept-Encoding, Authorization, Cache-Control, Content-Type, Content-Length, Origin, X-Real-IP, X-CSRF-Token") + + // CORS for Private Networks (RFC1918) + // @see https://developer.chrome.com/blog/private-network-access-update/?utm_source=devtools + if allowPrivateNetwork { + c.Header("Access-Control-Request-Private-Network", "true") + } + // Maximum age allowable under Chromium v76 is 2 hours, so just use that since // anything higher will be ignored (even if other browsers do allow higher values). // // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives c.Header("Access-Control-Max-Age", "7200") - c.Header("Access-Control-Allow-Origin", location) - c.Header("Access-Control-Allow-Headers", "Accept, Accept-Encoding, Authorization, Cache-Control, Content-Type, Content-Length, Origin, X-Real-IP, X-CSRF-Token") + // Validate that the request origin is coming from an allowed origin. Because you // cannot set multiple values here we need to see if the origin is one of the ones // that we allow, and if so return it explicitly. Otherwise, just return the default