From f56b1f44cfa2631d7627a493bde821d0184cc4d7 Mon Sep 17 00:00:00 2001 From: Christopher Vermilion Date: Mon, 21 Feb 2022 15:44:46 -0500 Subject: [PATCH] support Private Network Access spec Based on [this Chrome blog](https://developer.chrome.com/blog/private-network-access-preflight) and the related W3C [draft report](https://wicg.github.io/private-network-access). --- cors.go | 8 ++++++++ cors_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/cors.go b/cors.go index 2ce24e3..4fe1441 100644 --- a/cors.go +++ b/cors.go @@ -62,6 +62,9 @@ type Options struct { // AllowCredentials indicates whether the request can include user credentials like // cookies, HTTP authentication or client side SSL certificates. AllowCredentials bool + // AllowPrivateNetwork indicates whether to accept cross-origin requests over a + // private network. + AllowPrivateNetwork bool // OptionsPassthrough instructs preflight to let other potential next handlers to // process the OPTIONS method. Turn this on if your application handles OPTIONS. OptionsPassthrough bool @@ -103,6 +106,7 @@ type Cors struct { // Status code to use for successful OPTIONS requests optionsSuccessStatus int allowCredentials bool + allowPrivateNetwork bool optionPassthrough bool } @@ -113,6 +117,7 @@ func New(options Options) *Cors { allowOriginFunc: options.AllowOriginFunc, allowOriginRequestFunc: options.AllowOriginRequestFunc, allowCredentials: options.AllowCredentials, + allowPrivateNetwork: options.AllowPrivateNetwork, maxAge: options.MaxAge, optionPassthrough: options.OptionsPassthrough, } @@ -319,6 +324,9 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { if c.allowCredentials { headers.Set("Access-Control-Allow-Credentials", "true") } + if c.allowPrivateNetwork && r.Header.Get("Access-Control-Request-Private-Network") == "true" { + headers.Set("Access-Control-Allow-Private-Network", "true") + } if c.maxAge > 0 { headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge)) } diff --git a/cors_test.go b/cors_test.go index b4d6d5a..7947334 100644 --- a/cors_test.go +++ b/cors_test.go @@ -18,6 +18,7 @@ var allHeaders = []string{ "Access-Control-Allow-Methods", "Access-Control-Allow-Headers", "Access-Control-Allow-Credentials", + "Access-Control-Allow-Private-Network", "Access-Control-Max-Age", "Access-Control-Expose-Headers", } @@ -387,6 +388,44 @@ func TestSpec(t *testing.T) { }, true, }, + { + "AllowedPrivateNetwork", + Options{ + AllowedOrigins: []string{"http://foobar.com"}, + AllowPrivateNetwork: true, + }, + "OPTIONS", + map[string]string{ + "Origin": "http://foobar.com", + "Access-Control-Request-Method": "GET", + "Access-Control-Request-Private-Network": "true", + }, + map[string]string{ + "Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers", + "Access-Control-Allow-Origin": "http://foobar.com", + "Access-Control-Allow-Methods": "GET", + "Access-Control-Allow-Private-Network": "true", + }, + true, + }, + { + "DisallowedPrivateNetwork", + Options{ + AllowedOrigins: []string{"http://foobar.com"}, + }, + "OPTIONS", + map[string]string{ + "Origin": "http://foobar.com", + "Access-Control-Request-Method": "GET", + "Access-Control-Request-PrivateNetwork": "true", + }, + map[string]string{ + "Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers", + "Access-Control-Allow-Origin": "http://foobar.com", + "Access-Control-Allow-Methods": "GET", + }, + true, + }, { "OptionPassthrough", Options{