chore(deps): bump github.com/libregraph/lico

Bumps [github.com/libregraph/lico](https://github.com/libregraph/lico) from 0.60.1-0.20230811070109-1d4140be554d to 0.61.1.
- [Changelog](https://github.com/libregraph/lico/blob/master/CHANGELOG.md)
- [Commits](https://github.com/libregraph/lico/commits/v0.61.1)

---
updated-dependencies:
- dependency-name: github.com/libregraph/lico
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-12-05 09:40:36 +01:00
committed by Ralf Haferkamp
parent ee30eceb5d
commit a6a6c22c14
17 changed files with 347 additions and 2351 deletions
+13 -10
View File
@@ -1,4 +1,4 @@
# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![build](https://img.shields.io/travis/rs/cors.svg?style=flat)](https://travis-ci.org/rs/cors) [![Coverage](http://gocover.io/_badge/github.com/rs/cors)](http://gocover.io/github.com/rs/cors)
# Go CORS handler [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/cors) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [![Go Coverage](https://github.com/rs/cors/wiki/coverage.svg)](https://raw.githack.com/wiki/rs/cors/coverage.html)
CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang.
@@ -102,15 +102,18 @@ See [API documentation](http://godoc.org/github.com/rs/cors) for more info.
## Benchmarks
BenchmarkWithout 20000000 64.6 ns/op 8 B/op 1 allocs/op
BenchmarkDefault 3000000 469 ns/op 114 B/op 2 allocs/op
BenchmarkAllowedOrigin 3000000 608 ns/op 114 B/op 2 allocs/op
BenchmarkPreflight 20000000 73.2 ns/op 0 B/op 0 allocs/op
BenchmarkPreflightHeader 20000000 73.6 ns/op 0 B/op 0 allocs/op
BenchmarkParseHeaderList 2000000 847 ns/op 184 B/op 6 allocs/op
BenchmarkParse…Single 5000000 290 ns/op 32 B/op 3 allocs/op
BenchmarkParse…Normalized 2000000 776 ns/op 160 B/op 6 allocs/op
goos: darwin
goarch: arm64
pkg: github.com/rs/cors
BenchmarkWithout-10 352671961 3.317 ns/op 0 B/op 0 allocs/op
BenchmarkDefault-10 18261723 65.63 ns/op 0 B/op 0 allocs/op
BenchmarkAllowedOrigin-10 13309591 90.21 ns/op 0 B/op 0 allocs/op
BenchmarkPreflight-10 7247728 166.9 ns/op 0 B/op 0 allocs/op
BenchmarkPreflightHeader-10 5915437 202.9 ns/op 0 B/op 0 allocs/op
BenchmarkWildcard/match-10 250336476 4.784 ns/op 0 B/op 0 allocs/op
BenchmarkWildcard/too_short-10 1000000000 0.6354 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/rs/cors 9.613s
## Licenses
All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE).
+129 -74
View File
@@ -4,15 +4,15 @@ as defined by http://www.w3.org/TR/cors/
You can configure it by passing an option struct to cors.New:
c := cors.New(cors.Options{
AllowedOrigins: []string{"foo.com"},
AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete},
AllowCredentials: true,
})
c := cors.New(cors.Options{
AllowedOrigins: []string{"foo.com"},
AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete},
AllowCredentials: true,
})
Then insert the handler in the chain:
handler = c.Handler(handler)
handler = c.Handler(handler)
See Options documentation for more options.
@@ -28,6 +28,10 @@ import (
"strings"
)
var headerVaryOrigin = []string{"Origin"}
var headerOriginAll = []string{"*"}
var headerTrue = []string{"true"}
// Options is a configuration container to setup the CORS middleware.
type Options struct {
// AllowedOrigins is a list of origins a cross-domain request can be executed from.
@@ -37,27 +41,39 @@ type Options struct {
// Only one wildcard can be used per origin.
// Default value is ["*"]
AllowedOrigins []string
// AllowOriginFunc is a custom function to validate the origin. It take the origin
// as argument and returns true if allowed or false otherwise. If this option is
// set, the content of AllowedOrigins is ignored.
// AllowOriginFunc is a custom function to validate the origin. It take the
// origin as argument and returns true if allowed or false otherwise. If
// this option is set, the content of `AllowedOrigins` is ignored.
AllowOriginFunc func(origin string) bool
// AllowOriginRequestFunc is a custom function to validate the origin. It takes the HTTP Request object and the origin as
// argument and returns true if allowed or false otherwise. If this option is set, the content of `AllowedOrigins`
// and `AllowOriginFunc` is ignored.
// AllowOriginRequestFunc is a custom function to validate the origin. It
// takes the HTTP Request object and the origin as argument and returns true
// if allowed or false otherwise. If headers are used take the decision,
// consider using AllowOriginVaryRequestFunc instead. If this option is set,
// the content of `AllowedOrigins`, `AllowOriginFunc` are ignored.
AllowOriginRequestFunc func(r *http.Request, origin string) bool
// AllowOriginVaryRequestFunc is a custom function to validate the origin.
// It takes the HTTP Request object and the origin as argument and returns
// true if allowed or false otherwise with a list of headers used to take
// that decision if any so they can be added to the Vary header. If this
// option is set, the content of `AllowedOrigins`, `AllowOriginFunc` and
// `AllowOriginRequestFunc` are ignored.
AllowOriginVaryRequestFunc func(r *http.Request, origin string) (bool, []string)
// AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is simple methods (HEAD, GET and POST).
AllowedMethods []string
// AllowedHeaders is list of non simple headers the client is allowed to use with
// cross-domain requests.
// If the special "*" value is present in the list, all headers will be allowed.
// Default value is [] but "Origin" is always appended to the list.
// Default value is [].
AllowedHeaders []string
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
ExposedHeaders []string
// MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached
// can be cached. Default value is 0, which stands for no
// Access-Control-Max-Age header to be sent back, resulting in browsers
// using their default value (5s by spec). If you need to force a 0 max-age,
// set `MaxAge` to a negative value (ie: -1).
MaxAge int
// AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates.
@@ -73,6 +89,8 @@ type Options struct {
OptionsSuccessStatus int
// Debugging flag adds additional output to debug server side CORS issues
Debug bool
// Adds a custom logger, implies Debug is true
Logger Logger
}
// Logger generic interface for logger
@@ -89,16 +107,15 @@ type Cors struct {
// List of allowed origins containing wildcards
allowedWOrigins []wildcard
// Optional origin validator function
allowOriginFunc func(origin string) bool
// Optional origin validator (with request) function
allowOriginRequestFunc func(r *http.Request, origin string) bool
allowOriginFunc func(r *http.Request, origin string) (bool, []string)
// Normalized list of allowed headers
allowedHeaders []string
// Normalized list of allowed methods
allowedMethods []string
// Normalized list of exposed headers
// Pre-computed normalized list of exposed headers
exposedHeaders []string
maxAge int
// Pre-computed maxAge header value
maxAge []string
// Set to true when allowed origins contains a "*"
allowedOriginsAll bool
// Set to true when allowed headers contains a "*"
@@ -108,30 +125,40 @@ type Cors struct {
allowCredentials bool
allowPrivateNetwork bool
optionPassthrough bool
preflightVary []string
}
// New creates a new Cors handler with the provided options.
func New(options Options) *Cors {
c := &Cors{
exposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey),
allowOriginFunc: options.AllowOriginFunc,
allowOriginRequestFunc: options.AllowOriginRequestFunc,
allowCredentials: options.AllowCredentials,
allowPrivateNetwork: options.AllowPrivateNetwork,
maxAge: options.MaxAge,
optionPassthrough: options.OptionsPassthrough,
allowCredentials: options.AllowCredentials,
allowPrivateNetwork: options.AllowPrivateNetwork,
optionPassthrough: options.OptionsPassthrough,
Log: options.Logger,
}
if options.Debug && c.Log == nil {
c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
}
if options.AllowOriginVaryRequestFunc != nil {
c.allowOriginFunc = options.AllowOriginVaryRequestFunc
} else if options.AllowOriginRequestFunc != nil {
c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) {
return options.AllowOriginRequestFunc(r, origin), nil
}
} else if options.AllowOriginFunc != nil {
c.allowOriginFunc = func(r *http.Request, origin string) (bool, []string) {
return options.AllowOriginFunc(origin), nil
}
}
// Normalize options
// Note: for origins and methods matching, the spec requires a case-sensitive matching.
// Note: for origins matching, the spec requires a case-sensitive matching.
// As it may error prone, we chose to ignore the spec here.
// Allowed Origins
if len(options.AllowedOrigins) == 0 {
if options.AllowOriginFunc == nil && options.AllowOriginRequestFunc == nil {
if c.allowOriginFunc == nil {
// Default is all origins
c.allowedOriginsAll = true
}
@@ -160,10 +187,9 @@ func New(options Options) *Cors {
// Allowed Headers
if len(options.AllowedHeaders) == 0 {
// Use sensible defaults
c.allowedHeaders = []string{"Origin", "Accept", "Content-Type", "X-Requested-With"}
c.allowedHeaders = []string{"Accept", "Content-Type", "X-Requested-With"}
} else {
// Origin is always appended as some browsers will always request for this header at preflight
c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
c.allowedHeaders = convert(options.AllowedHeaders, http.CanonicalHeaderKey)
for _, h := range options.AllowedHeaders {
if h == "*" {
c.allowedHeadersAll = true
@@ -178,7 +204,7 @@ func New(options Options) *Cors {
// Default is spec's "simple" methods
c.allowedMethods = []string{http.MethodGet, http.MethodPost, http.MethodHead}
} else {
c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
c.allowedMethods = options.AllowedMethods
}
// Options Success Status Code
@@ -188,6 +214,25 @@ func New(options Options) *Cors {
c.optionsSuccessStatus = options.OptionsSuccessStatus
}
// Pre-compute exposed headers header value
if len(options.ExposedHeaders) > 0 {
c.exposedHeaders = []string{strings.Join(convert(options.ExposedHeaders, http.CanonicalHeaderKey), ", ")}
}
// Pre-compute prefight Vary header to save allocations
if c.allowPrivateNetwork {
c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network"}
} else {
c.preflightVary = []string{"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"}
}
// Precompute max-age
if options.MaxAge > 0 {
c.maxAge = []string{strconv.Itoa(options.MaxAge)}
} else if options.MaxAge < 0 {
c.maxAge = []string{"0"}
}
return c
}
@@ -284,18 +329,21 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
// Always set Vary headers
// see https://github.com/rs/cors/issues/10,
// https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
headers.Add("Vary", "Origin")
headers.Add("Vary", "Access-Control-Request-Method")
headers.Add("Vary", "Access-Control-Request-Headers")
if c.allowPrivateNetwork {
headers.Add("Vary", "Access-Control-Request-Private-Network")
if vary, found := headers["Vary"]; found {
headers["Vary"] = append(vary, c.preflightVary[0])
} else {
headers["Vary"] = c.preflightVary
}
allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin)
if len(additionalVaryHeaders) > 0 {
headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", "))
}
if origin == "" {
c.logf(" Preflight aborted: empty origin")
return
}
if !c.isOriginAllowed(r, origin) {
if !allowed {
c.logf(" Preflight aborted: origin '%s' not allowed", origin)
return
}
@@ -305,40 +353,41 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
c.logf(" Preflight aborted: method '%s' not allowed", reqMethod)
return
}
// Amazon API Gateway is sometimes feeding multiple values for
// Access-Control-Request-Headers in a way where r.Header.Values() picks
// them all up, but r.Header.Get() does not.
// I suspect it is something like this: https://stackoverflow.com/a/4371395
reqHeaderList := strings.Join(r.Header.Values("Access-Control-Request-Headers"), ",")
reqHeaders := parseHeaderList(reqHeaderList)
reqHeadersRaw := r.Header["Access-Control-Request-Headers"]
reqHeaders, reqHeadersEdited := convertDidCopy(splitHeaderValues(reqHeadersRaw), http.CanonicalHeaderKey)
if !c.areHeadersAllowed(reqHeaders) {
c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
return
}
if c.allowedOriginsAll {
headers.Set("Access-Control-Allow-Origin", "*")
headers["Access-Control-Allow-Origin"] = headerOriginAll
} else {
headers.Set("Access-Control-Allow-Origin", origin)
headers["Access-Control-Allow-Origin"] = r.Header["Origin"]
}
// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
// by Access-Control-Request-Method (if supported) can be enough
headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
headers["Access-Control-Allow-Methods"] = r.Header["Access-Control-Request-Method"]
if len(reqHeaders) > 0 {
// Spec says: Since the list of headers can be unbounded, simply returning supported headers
// from Access-Control-Request-Headers can be enough
headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
if reqHeadersEdited || len(reqHeaders) != len(reqHeadersRaw) {
headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
} else {
headers["Access-Control-Allow-Headers"] = reqHeadersRaw
}
}
if c.allowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
headers["Access-Control-Allow-Credentials"] = headerTrue
}
if c.allowPrivateNetwork && r.Header.Get("Access-Control-Request-Private-Network") == "true" {
headers.Set("Access-Control-Allow-Private-Network", "true")
headers["Access-Control-Allow-Private-Network"] = headerTrue
}
if c.maxAge > 0 {
headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
if len(c.maxAge) > 0 {
headers["Access-Control-Max-Age"] = c.maxAge
}
if c.Log != nil {
c.logf(" Preflight response headers: %v", headers)
}
c.logf(" Preflight response headers: %v", headers)
}
// handleActualRequest handles simple cross-origin requests, actual request or redirects
@@ -346,13 +395,22 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
headers := w.Header()
origin := r.Header.Get("Origin")
allowed, additionalVaryHeaders := c.isOriginAllowed(r, origin)
// Always set Vary, see https://github.com/rs/cors/issues/10
headers.Add("Vary", "Origin")
if vary, found := headers["Vary"]; found {
headers["Vary"] = append(vary, headerVaryOrigin[0])
} else {
headers["Vary"] = headerVaryOrigin
}
if len(additionalVaryHeaders) > 0 {
headers.Add("Vary", strings.Join(convert(additionalVaryHeaders, http.CanonicalHeaderKey), ", "))
}
if origin == "" {
c.logf(" Actual request no headers added: missing origin")
return
}
if !c.isOriginAllowed(r, origin) {
if !allowed {
c.logf(" Actual request no headers added: origin '%s' not allowed", origin)
return
}
@@ -363,21 +421,22 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
// We think it's a nice feature to be able to have control on those methods though.
if !c.isMethodAllowed(r.Method) {
c.logf(" Actual request no headers added: method '%s' not allowed", r.Method)
return
}
if c.allowedOriginsAll {
headers.Set("Access-Control-Allow-Origin", "*")
headers["Access-Control-Allow-Origin"] = headerOriginAll
} else {
headers.Set("Access-Control-Allow-Origin", origin)
headers["Access-Control-Allow-Origin"] = r.Header["Origin"]
}
if len(c.exposedHeaders) > 0 {
headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
headers["Access-Control-Expose-Headers"] = c.exposedHeaders
}
if c.allowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
headers["Access-Control-Allow-Credentials"] = headerTrue
}
if c.Log != nil {
c.logf(" Actual response added headers: %v", headers)
}
c.logf(" Actual response added headers: %v", headers)
}
// convenience method. checks if a logger is set.
@@ -390,33 +449,31 @@ func (c *Cors) logf(format string, a ...interface{}) {
// check the Origin of a request. No origin at all is also allowed.
func (c *Cors) OriginAllowed(r *http.Request) bool {
origin := r.Header.Get("Origin")
return c.isOriginAllowed(r, origin)
allowed, _ := c.isOriginAllowed(r, origin)
return allowed
}
// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (c *Cors) isOriginAllowed(r *http.Request, origin string) bool {
if c.allowOriginRequestFunc != nil {
return c.allowOriginRequestFunc(r, origin)
}
func (c *Cors) isOriginAllowed(r *http.Request, origin string) (allowed bool, varyHeaders []string) {
if c.allowOriginFunc != nil {
return c.allowOriginFunc(origin)
return c.allowOriginFunc(r, origin)
}
if c.allowedOriginsAll {
return true
return true, nil
}
origin = strings.ToLower(origin)
for _, o := range c.allowedOrigins {
if o == origin {
return true
return true, nil
}
}
for _, w := range c.allowedWOrigins {
if w.match(origin) {
return true
return true, nil
}
}
return false
return false, nil
}
// isMethodAllowed checks if a given method can be used as part of a cross-domain request
@@ -426,7 +483,6 @@ func (c *Cors) isMethodAllowed(method string) bool {
// If no method allowed, always return false, even for preflight request
return false
}
method = strings.ToUpper(method)
if method == http.MethodOptions {
// Always allow preflight requests
return true
@@ -446,7 +502,6 @@ func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
return true
}
for _, header := range requestedHeaders {
header = http.CanonicalHeaderKey(header)
found := false
for _, h := range c.allowedHeaders {
if h == header {
+48 -47
View File
@@ -1,8 +1,8 @@
package cors
import "strings"
const toLower = 'a' - 'A'
import (
"strings"
)
type converter func(string) string
@@ -15,57 +15,58 @@ func (w wildcard) match(s string) bool {
return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix)
}
// convert converts a list of string using the passed converter function
func convert(s []string, c converter) []string {
out := []string{}
for _, i := range s {
out = append(out, c(i))
// split compounded header values ["foo, bar", "baz"] -> ["foo", "bar", "baz"]
func splitHeaderValues(values []string) []string {
out := values
copied := false
for i, v := range values {
needsSplit := strings.IndexByte(v, ',') != -1
if !copied {
if needsSplit {
split := strings.Split(v, ",")
out = make([]string, i, len(values)+len(split)-1)
copy(out, values[:i])
for _, s := range split {
out = append(out, strings.TrimSpace(s))
}
copied = true
}
} else {
if needsSplit {
split := strings.Split(v, ",")
for _, s := range split {
out = append(out, strings.TrimSpace(s))
}
} else {
out = append(out, v)
}
}
}
return out
}
// parseHeaderList tokenize + normalize a string containing a list of headers
func parseHeaderList(headerList string) []string {
l := len(headerList)
h := make([]byte, 0, l)
upper := true
// Estimate the number headers in order to allocate the right splice size
t := 0
for i := 0; i < l; i++ {
if headerList[i] == ',' {
t++
}
}
headers := make([]string, 0, t)
for i := 0; i < l; i++ {
b := headerList[i]
switch {
case b >= 'a' && b <= 'z':
if upper {
h = append(h, b-toLower)
} else {
h = append(h, b)
}
case b >= 'A' && b <= 'Z':
if !upper {
h = append(h, b+toLower)
} else {
h = append(h, b)
}
case b == '-' || b == '_' || b == '.' || (b >= '0' && b <= '9'):
h = append(h, b)
}
// convert converts a list of string using the passed converter function
func convert(s []string, c converter) []string {
out, _ := convertDidCopy(s, c)
return out
}
if b == ' ' || b == ',' || i == l-1 {
if len(h) > 0 {
// Flush the found header
headers = append(headers, string(h))
h = h[:0]
upper = true
// convertDidCopy is same as convert but returns true if it copied the slice
func convertDidCopy(s []string, c converter) ([]string, bool) {
out := s
copied := false
for i, v := range s {
if !copied {
v2 := c(v)
if v2 != v {
out = make([]string, len(s))
copy(out, s[:i])
out[i] = v2
copied = true
}
} else {
upper = b == '-' || b == '_'
out[i] = c(v)
}
}
return headers
return out, copied
}