From 05a7580bf9aa7c76045b5bb76258a679c1b973c2 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 8 Oct 2017 16:52:58 -0700 Subject: [PATCH 001/736] disambiguate debug messages --- handlers/handlers.go | 4 +++- pkg/domains/domains.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index d164a066..46e11d52 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -100,9 +100,11 @@ func loginURL(r *http.Request, state string) string { // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var url = "" if gcred.ClientID != "" { + // If the provider is Google, find a matching redirect URL to use for the client domain := domains.Matches(r.Host) + log.Debugf("looking for redirect URL matching %v", domain) for i, v := range gcred.RedirectURLs { - log.Debugf("array value at [%d]=%v", i, v) + log.Debugf("redirect value matched at [%d]=%v", i, v) if strings.Contains(v, domain) { oauthclient.RedirectURL = v break diff --git a/pkg/domains/domains.go b/pkg/domains/domains.go index 076e550e..ce6c8453 100644 --- a/pkg/domains/domains.go +++ b/pkg/domains/domains.go @@ -14,7 +14,7 @@ import ( // TODO return all matches func Matches(s string) string { for i, v := range cfg.Cfg.Domains { - log.Debugf("array value at [%d]=%v", i, v) + log.Debugf("domain matched array value at [%d]=%v", i, v) if strings.Contains(s, v) { return v } From 31b490992764e92b1d99bed207da7dabb11c6972 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 8 Oct 2017 16:53:44 -0700 Subject: [PATCH 002/736] fix redirect URL for generic provider --- pkg/structs/structs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index a11185d6..5f98f491 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -46,7 +46,7 @@ type GenericOauth struct { ClientSecret string `mapstructure:"client_secret"` AuthURL string `mapstructure:"auth_url"` TokenURL string `mapstructure:"token_url"` - RedirectURL string `mapstructure:"callback_url "` + RedirectURL string `mapstructure:"callback_url"` Scopes []string `mapstructure:"scopes"` UserInfoURL string `mapstructure:"user_info_url"` Provider string `mapstructure:"provider"` From 323a568c712b3a4a71afa84106553661d547e6e9 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 8 Oct 2017 18:27:13 -0700 Subject: [PATCH 003/736] allow forcing the domain of the cookie to set --- config/config.yml_example | 2 ++ pkg/cfg/cfg.go | 1 + pkg/cookie/cookie.go | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/config/config.yml_example b/config/config.yml_example index 8db4cc42..724eec55 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -21,6 +21,8 @@ lasso: cookie: # name of cookie to store the jwt name: Lasso + # optionally force the domain of the cookie to set + # domain: yourdomain.com secure: false httpOnly: true headers: diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 2c2e4a23..3b135fb6 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -23,6 +23,7 @@ type CfgT struct { } Cookie struct { Name string `mapstructure:"name"` + Domain string `mapstructure:"domain"` Secure bool `mapstructure:"secure"` HTTPOnly bool `mapstructure:"httpOnly"` } diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index 72d3dd3e..e8c9baa5 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -23,6 +23,11 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { maxAge = defaultMaxAge } domain := domains.Matches(r.Host) + // Allow overriding the cookie domain in the config file + if cfg.Cfg.Cookie.Domain != "" { + domain = cfg.Cfg.Cookie.Domain + log.Debugf("setting the cookie domain to %v", domain) + } // log.Debugf("cookie %s expires %d", cfg.Cfg.Cookie.Name, expires) http.SetCookie(w, &http.Cookie{ Name: cfg.Cfg.Cookie.Name, From 7588a21fd8f28cfefa49faae3d76b334fac07c93 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 8 Oct 2017 18:30:46 -0700 Subject: [PATCH 004/736] add option to allow all users will not reject any user based on domain matching. useful when using Lasso to identify users rather than determine whether they are authorized. --- config/config.yml_example | 2 ++ handlers/handlers.go | 9 ++++++--- pkg/cfg/cfg.go | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index 8db4cc42..d5626786 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -7,6 +7,8 @@ lasso: logLevel: info listen: 0.0.0.0 port: 9090 + # set allowAllUsers: true to use Lasso to just identify users rather than determine whether they are authorized + allowAllUsers: false # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... # usually you'll just have one domains: diff --git a/handlers/handlers.go b/handlers/handlers.go index 46e11d52..30451592 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -201,9 +201,11 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } log.Infof("email from jwt cookie: %s", claims.Email) - if !jwtmanager.SiteInClaims(r.Host, &claims) { - error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) - return + if !cfg.Cfg.AllowAllUsers { + if !jwtmanager.SiteInClaims(r.Host, &claims) { + error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) + return + } } // renderIndex(w, "user found from email "+user.Email) @@ -325,6 +327,7 @@ func VerifyUser(u interface{}) (ok bool, err error) { // } else if !domains.IsUnderManagement(user.HostDomain) { // err = fmt.Errorf("HostDomain %s is not within a lasso managed domain", u.HostDomain) } else { + log.Debugf("no domains configured") ok = true } return ok, err diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 2c2e4a23..5bae7274 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -15,6 +15,7 @@ type CfgT struct { Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` Domains []string `mapstructure:"domains"` + AllowAllUsers bool `mapstructure:"allowAllUsers"` JWT struct { MaxAge int `mapstructure:"maxAge"` Issuer string `mapstructure:"issuer"` From 1b7e9677835c87af95047fbcc1757c061a0c2dee Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 8 Oct 2017 20:32:22 -0700 Subject: [PATCH 005/736] add config option to allow public access setting `publicAccess: true` tells Lasso to allow requests even without a cookie. this is useful for public sites that also allow users to sign in. --- config/config.yml_example | 2 ++ handlers/handlers.go | 7 ++++++- pkg/cfg/cfg.go | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/config.yml_example b/config/config.yml_example index 8db4cc42..fdc692ae 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -7,6 +7,8 @@ lasso: logLevel: info listen: 0.0.0.0 port: 9090 + # Setting publicAccess: true will accept all requests, even without a cookie. If the user is logged in, the cookie will be validated and the user header will be set. + publicAccess: false # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... # usually you'll just have one domains: diff --git a/handlers/handlers.go b/handlers/handlers.go index 46e11d52..0adf35ab 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -184,7 +184,12 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { jwt := FindJWT(r) // if jwt != "" { if jwt == "" { - error401(w, r, AuthError{Error: "no jwt found"}) + // If the module is configured to allow public access with no authentication, return 200 now + if !cfg.Cfg.PublicAccess { + error401(w, r, AuthError{Error: "no jwt found"}) + } else { + w.Header().Add("X-Lasso-User", ""); + } return } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 2c2e4a23..83724a78 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -15,6 +15,7 @@ type CfgT struct { Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` Domains []string `mapstructure:"domains"` + PublicAccess bool `mapstructure:"publicAccess"` JWT struct { MaxAge int `mapstructure:"maxAge"` Issuer string `mapstructure:"issuer"` From 90654ffd1cabb10954f94710e52bae27f289eb94 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 10 Oct 2017 05:48:37 -0700 Subject: [PATCH 006/736] document X-Lasso-User --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0235ee2c..414a2e1e 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,8 @@ server { proxy_pass_request_body off; proxy_set_header Content-Length ""; - # not currently - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + # pass X-Lasso-User along with the request + auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user; # these return values are used by the @error401 call auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt; @@ -50,6 +48,13 @@ server { # redirect to lasso for login return 302 https://lasso.yourdomain.com:9090/login?url=$scheme://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err; } + + # proxy pass authorized requests to your service + location / { + proxy_pass http://dev.yourdomain.com:8080; + # set user header (usually an email) + proxy_set_header X-Lasso-User $auth_resp_x_lasso_user; + } } ``` From bc081e9639a32eeef4cf3f446bfaa80fed8abdf7 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 10 Oct 2017 05:48:57 -0700 Subject: [PATCH 007/736] run, build --- do.sh | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/do.sh b/do.sh index 779d51cf..78afcf5d 100755 --- a/do.sh +++ b/do.sh @@ -14,6 +14,14 @@ NAME=lasso HTTPPORT=9090 GODOC_PORT=5050 +run () { + go run main.go +} + +build () { + go build . +} + gogo () { docker run --rm -i -t -v /var/run/docker.sock:/var/run/docker.sock -v ${SDIR}/go:/go --name gogo $GOIMAGE $* } @@ -112,14 +120,16 @@ browsebolt() { usage() { cat < lasso_flow.jpg + $0 graphviz - lasso_flow.dot --> lasso_flow.jpg do is like make @@ -130,41 +140,13 @@ EOF ARG=$1; shift; case "$ARG" in - 'browsebolt') - browsebolt - ;; - - 'build') - dbuild - ;; - 'drun') - drun $* - ;; - 'revproxy') - revproxy $* - ;; - 'graphviz') - graphviz $* - ;; - 'test') - test $* + 'run'|'build'|'browsebolt'|'dbuild'|'drun'|'revproxy'|'graphviz'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic') + $ARG $* ;; 'godoc') echo "godoc running at http://${GODOC_PORT}" godoc -http=:${GODOC_PORT} ;; - 'goget'|'get') - goget $* - ;; - 'gogo') - gogo $* - ;; - 'watch') - watch $* - ;; - 'gobuildstatic') - gobuildstatic $* - ;; 'all') gobuildstatic dbuild From a9fefa63c37ae38d5fdcbc87b2680b36c2adda70 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 18 Oct 2017 17:30:45 -0700 Subject: [PATCH 008/736] commit fixed conficts --- config/config.yml_example | 3 --- pkg/cfg/cfg.go | 17 +++++++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index cc61fa7b..a4b26817 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -7,13 +7,10 @@ lasso: logLevel: info listen: 0.0.0.0 port: 9090 -<<<<<<< HEAD # set allowAllUsers: true to use Lasso to just identify users rather than determine whether they are authorized allowAllUsers: false -======= # Setting publicAccess: true will accept all requests, even without a cookie. If the user is logged in, the cookie will be validated and the user header will be set. publicAccess: false ->>>>>>> de8e608275cddf7f25904a3565fc3df71bd8fa29 # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... # usually you'll just have one domains: diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 2738a914..9b936f59 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -11,16 +11,13 @@ import ( // CfgT lasso jwt cookie configuration type CfgT struct { - LogLevel string `mapstructure:"logLevel"` - Listen string `mapstructure:"listen"` - Port int `mapstructure:"port"` - Domains []string `mapstructure:"domains"` -<<<<<<< HEAD - AllowAllUsers bool `mapstructure:"allowAllUsers"` -======= - PublicAccess bool `mapstructure:"publicAccess"` ->>>>>>> de8e608275cddf7f25904a3565fc3df71bd8fa29 - JWT struct { + LogLevel string `mapstructure:"logLevel"` + Listen string `mapstructure:"listen"` + Port int `mapstructure:"port"` + Domains []string `mapstructure:"domains"` + AllowAllUsers bool `mapstructure:"allowAllUsers"` + PublicAccess bool `mapstructure:"publicAccess"` + JWT struct { MaxAge int `mapstructure:"maxAge"` Issuer string `mapstructure:"issuer"` Secret string `mapstructure:"secret"` From 5adc14e6266480782275090f8d1e5c257603406f Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sat, 2 Dec 2017 13:35:45 -0800 Subject: [PATCH 009/736] add `url` param to logout route allows redirecting elsewhere when logging out --- handlers/handlers.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index eaa85ef3..70dec5f4 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -256,7 +256,13 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { } session.Save(r, w) sessstore.MaxAge(300) - renderIndex(w, "you have been logged out") + + var redirectURL = r.URL.Query().Get("url") + if redirectURL != "" { + http.Redirect(w, r, redirectURL, 302); + } else { + renderIndex(w, "you have been logged out") + } } // LoginHandler /login From cbd3917122cee683237b317e13135f362bfeac04 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 4 Dec 2017 07:28:03 -0800 Subject: [PATCH 010/736] don't crash on invalid cookie data --- pkg/jwtmanager/jwtmanager.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 1d38d3c7..58865906 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -170,16 +170,16 @@ func decodeAndDecompressTokenString(encgzipss string) string { // gzipss, err := url.QueryUnescape(encgzipss) gzipss, err := base64.URLEncoding.DecodeString(encgzipss) if err != nil { - log.Fatal(err) + log.Debugf("Error in Base64decode: %v", err) } breader := bytes.NewReader(gzipss) zr, err := gzip.NewReader(breader) if err != nil { - log.Fatal(err) + log.Debugf("Error reading gzip data: %v", err) } if err := zr.Close(); err != nil { - log.Fatal(err) + log.Debugf("Error decoding token: %v", err) } ss, _ := ioutil.ReadAll(zr) return string(ss) From a71e788d6a23f698a3e35f79af20b68521f6b663 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 4 Dec 2017 07:58:42 -0800 Subject: [PATCH 011/736] don't continue processing on invalid gzip data closes #10 --- pkg/jwtmanager/jwtmanager.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 58865906..d9d61e05 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -177,6 +177,7 @@ func decodeAndDecompressTokenString(encgzipss string) string { zr, err := gzip.NewReader(breader) if err != nil { log.Debugf("Error reading gzip data: %v", err) + return "" } if err := zr.Close(); err != nil { log.Debugf("Error decoding token: %v", err) From f09ec4078698832551152477575139f3062c5b8e Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 4 Dec 2017 08:05:33 -0800 Subject: [PATCH 012/736] use OAuth 2.0 Bearer Token when looking for token Modifies `FindJWT` function to also look in the `Authorization` header for an OAuth 2.0 Bearer Token, e.g. `Authorization: Bearer XXXXXXX` Adds a new config item to set the query string param separately from the HTTP header, so if you set it to `access_token` then it also follows the Bearer Token spec. --- config/config.yml_example | 3 ++- handlers/handlers.go | 37 ++++++++++++++++++++++++------------- pkg/cfg/cfg.go | 3 ++- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index a4b26817..9a24a4dd 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -30,7 +30,8 @@ lasso: secure: false httpOnly: true headers: - sso: X-Lasso-Token + jwt: X-Lasso-Token + querystring: access_token redirect: X-Lasso-Requested-URI db: file: data/lasso_bolt.db diff --git a/handlers/handlers.go b/handlers/handlers.go index 70dec5f4..d1cfcccb 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -119,23 +119,34 @@ func loginURL(r *http.Request, state string) string { return url } -// FindJWT look for JWT in Cookie, Header and Query String in that order +// FindJWT look for JWT in Cookie, JWT Header, Authorization Header (OAuth 2 Bearer Token) +// and Query String in that order func FindJWT(r *http.Request) string { jwt, err := cookie.Cookie(r) - if err != nil { - log.Error(err) - // return "" - } - log.Debugf("jwtCookie from cookie: %s", jwt) - if jwt == "" { - jwt = r.Header.Get(cfg.Cfg.Headers.SSO) - log.Debugf("jwtCookie from header %s: %s", cfg.Cfg.Headers.SSO, jwt) + if err == nil { + log.Debugf("jwt from cookie: %s", jwt) + return jwt + } + jwt = r.Header.Get(cfg.Cfg.Headers.JWT) + if jwt != "" { + log.Debugf("jwt from header %s: %s", cfg.Cfg.Headers.JWT, jwt) + return jwt + } + auth := r.Header.Get("Authorization") + if auth != "" { + s := strings.SplitN(auth, " ", 2) + if len(s) == 2 { + jwt = s[1] + log.Debugf("jwt from authorization header: %s", jwt) + return jwt + } } - if jwt == "" { - jwt = r.URL.Query().Get(cfg.Cfg.Headers.SSO) - log.Debugf("jwtCookie from querystring %s: %s", cfg.Cfg.Headers.SSO, jwt) + jwt = r.URL.Query().Get(cfg.Cfg.Headers.QueryString) + if jwt != "" { + log.Debugf("jwt from querystring %s: %s", cfg.Cfg.Headers.QueryString, jwt) + return jwt } - return jwt + return "" } // ClaimsFromJWT look everywhere for the JWT, then parse the jwt and return the claims diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 9b936f59..41b90e24 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -30,7 +30,8 @@ type CfgT struct { HTTPOnly bool `mapstructure:"httpOnly"` } Headers struct { - SSO string `mapstructure:"sso"` + JWT string `mapstructure:"jwt"` + QueryString string `mapstructure:"querystring"` Redirect string `mapstructure:"redirect"` } DB struct { From fd792b237fc58aea85c311b182356a0950d5a92c Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Thu, 7 Dec 2017 11:04:45 -0800 Subject: [PATCH 013/736] fix for PublicAccess=true was previously returning 401 when an invalid JWT was sent, rather than allowing but setting the user to a blank string --- handlers/handlers.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 70dec5f4..9d9c72ba 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -196,19 +196,31 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { claims, err := ClaimsFromJWT(jwt) if err != nil { // no email in jwt - error401(w, r, AuthError{err.Error(), jwt}) + if !cfg.Cfg.PublicAccess { + error401(w, r, AuthError{err.Error(), jwt}) + } else { + w.Header().Add("X-Lasso-User", ""); + } return } if claims.Email == "" { // no email in jwt - error401(w, r, AuthError{"no email found in jwt", jwt}) + if !cfg.Cfg.PublicAccess { + error401(w, r, AuthError{"no email found in jwt", jwt}) + } else { + w.Header().Add("X-Lasso-User", ""); + } return } log.Infof("email from jwt cookie: %s", claims.Email) if !cfg.Cfg.AllowAllUsers { if !jwtmanager.SiteInClaims(r.Host, &claims) { - error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) + if !cfg.Cfg.PublicAccess { + error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) + } else { + w.Header().Add("X-Lasso-User", ""); + } return } } From ef218fd334f57e242f2bcf1e62e7c1aff203a329 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 10 Aug 2018 16:11:45 -0700 Subject: [PATCH 014/736] add support for OpenID Connect providers --- handlers/handlers.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/handlers/handlers.go b/handlers/handlers.go index fa380c48..f930a5f9 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -450,6 +450,28 @@ func getUserInfo(r *http.Request, user *structs.User) error { return getUserInfoFromGoogle(client, user) } else if genOauth.Provider == "github" { return getUserInfoFromGithub(client, user, providerToken) + } else if genOauth.Provider == "oidc" { + return getUserInfoFromOpenID(client, user, providerToken) + } else { + log.Error("we don't know how to look up the user info") + } + return nil +} + +func getUserInfoFromOpenID(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { + userinfo, err := client.Get(genOauth.UserInfoURL) + if err != nil { + // http.Error(w, err.Error(), http.StatusBadRequest) + return err + } + defer userinfo.Body.Close() + data, _ := ioutil.ReadAll(userinfo.Body) + log.Println("OpenID userinfo body: ", string(data)) + if err = json.Unmarshal(data, user); err != nil { + log.Errorln(err) + // renderIndex(w, "Error marshalling response. Please try agian.") + // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) + return err } return nil } From 3bf1397c71083426d6acb436f81caf11292347c8 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 10 Aug 2018 16:58:03 -0700 Subject: [PATCH 015/736] drop special-casing google credentials * changes config file format to drop the extra level of nesting * update example config with more explanations * Use more different names for lasso cookie vs session to be less confused when looking at the debug logs --- config/config.yml_example | 107 ++++++++++++++++++++------------------ handlers/handlers.go | 67 ++++++++++++------------ pkg/structs/structs.go | 11 +--- 3 files changed, 90 insertions(+), 95 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index 9a24a4dd..5611abf4 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -1,22 +1,21 @@ - # lasso config - - lasso: # logLevel: debug logLevel: info listen: 0.0.0.0 port: 9090 - # set allowAllUsers: true to use Lasso to just identify users rather than determine whether they are authorized + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider allowAllUsers: false - # Setting publicAccess: true will accept all requests, even without a cookie. If the user is logged in, the cookie will be validated and the user header will be set. + # Setting publicAccess: true will accept all requests, even without a cookie. + # If the user is logged in, the cookie will be validated and the user header will be set. + # You will need to direct people to the Lasso login page from your application. publicAccess: false # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... - # usually you'll just have one + # usually you'll just have one. + # Comment this out if you set allowAllUser:true domains: - yourdomain.com - yourotherdomain.com - # gets sent to google as a primer jwt: issuer: Lasso maxAge: 240 @@ -24,10 +23,10 @@ lasso: compress: true cookie: # name of cookie to store the jwt - name: Lasso + name: Lasso-cookie # optionally force the domain of the cookie to set # domain: yourdomain.com - secure: false + secure: true httpOnly: true headers: jwt: X-Lasso-Token @@ -36,50 +35,56 @@ lasso: db: file: data/lasso_bolt.db session: - name: lasso - test_url: http://my.testing.site.com + name: lasso-session + test_url: http://yourdomain.com # -# OAuth Config +# OAuth Provider Config # oauth: - # configure one of the following - google: - # create new credentials at: - # https://console.developers.google.com/apis/credentials - client_id: - client_secret: - # must be the /auth endpoint - callback_urls: - - http://lasso.yourdomain.com:9090/auth - - http://lasso.yourotherdomain.com:9090/auth - preferredDomain: yourdomain.com - generic: - # create new credentials at: - # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ - provider: github - client_id: - client_secret: - auth_url: https://github.com/login/oauth/authorize - token_url: https://github.com/login/oauth/access_token - # callback_url is configured at github.com when setting up the app - scopes: - - user - user_info_url: https://api.github.com/user?access_token= - generic: - # https://indieauth.com/developers - provider: indieauth - client_id: http://yourdomain.com - # must be the /auth endpoint - auth_url: https://indieauth.com/auth - user_info_url: https://indieauth.com/auth - callback_url: http://lasso.yourdomain.com:9090/auth - generic: - # https://indieauth.com/developers - provider: indieauth - client_id: http://yourdomain.com - # must be the /auth endpoint - auth_url: https://indieauth.com/auth - user_info_url: https://indieauth.com/auth - callback_url: http://lasso.yourdomain.com:9090/auth + # configure only one of the following + + # Google + provider: google + # create new credentials at: + # https://console.developers.google.com/apis/credentials + client_id: + client_secret: + # must be the /auth endpoint + callback_urls: + - http://lasso.yourdomain.com:9090/auth + - http://lasso.yourotherdomain.com:9090/auth + preferredDomain: yourdomain.com + + # GitHub + # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ + provider: github + client_id: + client_secret: + auth_url: https://github.com/login/oauth/authorize + token_url: https://github.com/login/oauth/access_token + # callback_url is configured at github.com when setting up the app + scopes: + - user + user_info_url: https://api.github.com/user?access_token= + + # Generic OpenID Connect + provider: oidc + client_id: + client_secret: + auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize + token_url: https://{yourOktaDomain}/oauth2/default/v1/token + user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo + scopes: + - openid + - email + - profile + callback_url: http://lasso.yourdomain.com:9090/auth + + # IndieAuth + # https://indielogin.com/api + provider: indieauth + client_id: http://yourdomain.com + auth_url: https://indielogin.com/auth + callback_url: http://lasso.yourdomain.com:9090/auth diff --git a/handlers/handlers.go b/handlers/handlers.go index f930a5f9..018a9846 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -40,7 +40,6 @@ type AuthError struct { } var ( - gcred structs.GCredentials genOauth structs.GenericOauth oauthclient *oauth2.Config oauthopts oauth2.AuthCodeOption @@ -54,37 +53,34 @@ var ( func init() { log.Debug("init handlers") - // if grcred exist - err := cfg.UnmarshalKey("oauth.google", &gcred) - if err == nil && gcred.ClientID != "" { - log.Info("configuring google oauth") - oauthclient = &oauth2.Config{ - ClientID: gcred.ClientID, - ClientSecret: gcred.ClientSecret, - // RedirectURL: gcred.RedirectURL, - Scopes: []string{ - // You have to select a scope from - // https://developers.google.com/identity/protocols/googlescopes#google_sign-in - "https://www.googleapis.com/auth/userinfo.email", - }, - Endpoint: google.Endpoint, - } - log.Infof("setting google oauth prefered login domain param 'hd' to %s", gcred.PreferredDomain) - oauthopts = oauth2.SetAuthURLParam("hd", gcred.PreferredDomain) - return - } - err = cfg.UnmarshalKey("oauth.generic", &genOauth) + err := cfg.UnmarshalKey("oauth", &genOauth) if err == nil { - log.Info("configuring generic oauth") - oauthclient = &oauth2.Config{ - ClientID: genOauth.ClientID, - ClientSecret: genOauth.ClientSecret, - Endpoint: oauth2.Endpoint{ - AuthURL: genOauth.AuthURL, - TokenURL: genOauth.TokenURL, - }, - RedirectURL: genOauth.RedirectURL, - Scopes: genOauth.Scopes, + if genOauth.Provider == "google" { + log.Info("configuring google oauth") + oauthclient = &oauth2.Config{ + ClientID: genOauth.ClientID, + ClientSecret: genOauth.ClientSecret, + Scopes: []string{ + // You have to select a scope from + // https://developers.google.com/identity/protocols/googlescopes#google_sign-in + "https://www.googleapis.com/auth/userinfo.email", + }, + Endpoint: google.Endpoint, + } + log.Infof("setting google oauth preferred login domain param 'hd' to %s", genOauth.PreferredDomain) + oauthopts = oauth2.SetAuthURLParam("hd", genOauth.PreferredDomain) + } else { + log.Info("configuring generic oauth") + oauthclient = &oauth2.Config{ + ClientID: genOauth.ClientID, + ClientSecret: genOauth.ClientSecret, + Endpoint: oauth2.Endpoint{ + AuthURL: genOauth.AuthURL, + TokenURL: genOauth.TokenURL, + }, + RedirectURL: genOauth.RedirectURL, + Scopes: genOauth.Scopes, + } } } } @@ -99,11 +95,11 @@ func loginURL(r *http.Request, state string) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var url = "" - if gcred.ClientID != "" { + if genOauth.Provider == "google" { // If the provider is Google, find a matching redirect URL to use for the client domain := domains.Matches(r.Host) log.Debugf("looking for redirect URL matching %v", domain) - for i, v := range gcred.RedirectURLs { + for i, v := range genOauth.RedirectURLs { log.Debugf("redirect value matched at [%d]=%v", i, v) if strings.Contains(v, domain) { oauthclient.RedirectURL = v @@ -401,7 +397,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { if ok, err := VerifyUser(user); !ok { log.Error(err) - renderIndex(w, fmt.Sprintf("User is not authorized. %s Please try agian.", err)) + renderIndex(w, fmt.Sprintf("User is not authorized. %s Please try again.", err)) return } @@ -444,9 +440,10 @@ func getUserInfo(r *http.Request, user *structs.User) error { if err != nil { return err } + // make the "third leg" request back to google to exchange the token for the userinfo client := oauthclient.Client(oauth2.NoContext, providerToken) - if gcred.ClientID != "" { + if genOauth.Provider == "google" { return getUserInfoFromGoogle(client, user) } else if genOauth.Provider == "github" { return getUserInfoFromGithub(client, user, providerToken) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 5f98f491..43f957c0 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -31,15 +31,6 @@ type GithubUser struct { // jwt.StandardClaims } -// GCredentials google credentials -// loaded from yaml config -type GCredentials struct { - ClientID string `mapstructure:"client_id"` - ClientSecret string `mapstructure:"client_secret"` - RedirectURLs []string `mapstructure:"callback_urls"` - PreferredDomain string `mapstructre:"preferredDomain"` -} - // GenericOauth provides endoint for access type GenericOauth struct { ClientID string `mapstructure:"client_id"` @@ -47,9 +38,11 @@ type GenericOauth struct { AuthURL string `mapstructure:"auth_url"` TokenURL string `mapstructure:"token_url"` RedirectURL string `mapstructure:"callback_url"` + RedirectURLs []string `mapstructure:"callback_urls"` Scopes []string `mapstructure:"scopes"` UserInfoURL string `mapstructure:"user_info_url"` Provider string `mapstructure:"provider"` + PreferredDomain string `mapstructre:"preferredDomain"` } // Team has members and provides acess to sites From 5228d7e05037216d0611830f21935fe6d035e47d Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 17 Aug 2018 14:44:06 -0400 Subject: [PATCH 016/736] move to LassoProject org --- Dockerfile | 6 +++--- do.sh | 2 +- handlers/handlers.go | 14 +++++++------- main.go | 10 +++++----- pkg/cfg/cfg_test.go | 2 +- pkg/cookie/cookie.go | 6 +++--- pkg/domains/domains.go | 2 +- pkg/jwtmanager/jwtmanager.go | 4 ++-- pkg/jwtmanager/jwtmanager_test.go | 4 ++-- pkg/model/model.go | 2 +- pkg/model/model_test.go | 2 +- pkg/model/site.go | 2 +- pkg/model/team.go | 2 +- pkg/model/user.go | 2 +- pkg/timelog/timelog.go | 2 +- pkg/transciever/client.go | 4 ++-- 16 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Dockerfile b/Dockerfile index e2f797e9..8664a808 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # bfoote/lasso -# https://github.com/bnfinet/lasso +# https://github.com/LassoProject/lasso FROM golang:1.8 -RUN mkdir -p ${GOPATH}/src/github.com/bnfinet/lasso -WORKDIR ${GOPATH}/src/github.com/bnfinet/lasso +RUN mkdir -p ${GOPATH}/src/github.com/LassoProject/lasso +WORKDIR ${GOPATH}/src/github.com/LassoProject/lasso COPY . . diff --git a/do.sh b/do.sh index 78afcf5d..1c552444 100755 --- a/do.sh +++ b/do.sh @@ -6,7 +6,7 @@ SCRIPT=$(readlink -f "$0") SDIR=$(dirname "$SCRIPT") cd $SDIR -export LASSO_ROOT=${GOPATH}/src/github.com/bnfinet/lasso/ +export LASSO_ROOT=${GOPATH}/src/github.com/LassoProject/lasso/ IMAGE=bfoote/lasso GOIMAGE=golang:1.8 diff --git a/handlers/handlers.go b/handlers/handlers.go index 018a9846..49fffee4 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -15,13 +15,13 @@ import ( log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/pkg/cfg" - lctx "github.com/bnfinet/lasso/pkg/context" - "github.com/bnfinet/lasso/pkg/cookie" - "github.com/bnfinet/lasso/pkg/domains" - "github.com/bnfinet/lasso/pkg/jwtmanager" - "github.com/bnfinet/lasso/pkg/model" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/cfg" + lctx "github.com/LassoProject/lasso/pkg/context" + "github.com/LassoProject/lasso/pkg/cookie" + "github.com/LassoProject/lasso/pkg/domains" + "github.com/LassoProject/lasso/pkg/jwtmanager" + "github.com/LassoProject/lasso/pkg/model" + "github.com/LassoProject/lasso/pkg/structs" "github.com/gorilla/sessions" "golang.org/x/oauth2" "golang.org/x/oauth2/google" diff --git a/main.go b/main.go index 5cc3b906..764cb977 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main // lasso -// github.com/bnfinet/lasso +// github.com/LassoProject/lasso import ( "net/http" @@ -10,10 +10,10 @@ import ( log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/handlers" - "github.com/bnfinet/lasso/pkg/cfg" - "github.com/bnfinet/lasso/pkg/timelog" - tran "github.com/bnfinet/lasso/pkg/transciever" + "github.com/LassoProject/lasso/handlers" + "github.com/LassoProject/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/timelog" + tran "github.com/LassoProject/lasso/pkg/transciever" ) func main() { diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 86fb5ead..c8a21064 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -2,7 +2,7 @@ package cfg import ( "testing" - // "github.com/bnfinet/lasso/pkg/structs" + // "github.com/LassoProject/lasso/pkg/structs" // log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus" "github.com/stretchr/testify/assert" diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index e8c9baa5..a5ad22ee 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -4,9 +4,9 @@ import ( "errors" "net/http" - // "github.com/bnfinet/lasso/pkg/structs" - "github.com/bnfinet/lasso/pkg/cfg" - "github.com/bnfinet/lasso/pkg/domains" + // "github.com/LassoProject/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/domains" log "github.com/Sirupsen/logrus" ) diff --git a/pkg/domains/domains.go b/pkg/domains/domains.go index ce6c8453..aec4bd59 100644 --- a/pkg/domains/domains.go +++ b/pkg/domains/domains.go @@ -3,7 +3,7 @@ package domains import ( "strings" - "github.com/bnfinet/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/cfg" log "github.com/Sirupsen/logrus" ) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index d9d61e05..f15ad60e 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -11,8 +11,8 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/pkg/cfg" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/structs" jwt "github.com/dgrijalva/jwt-go" ) diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index ed08027a..b9211cd7 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -3,8 +3,8 @@ package jwtmanager import ( "testing" - "github.com/bnfinet/lasso/pkg/cfg" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/structs" // log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus" "github.com/stretchr/testify/assert" diff --git a/pkg/model/model.go b/pkg/model/model.go index 83b74110..6dd8e2b4 100644 --- a/pkg/model/model.go +++ b/pkg/model/model.go @@ -8,7 +8,7 @@ import ( "os" "time" - "github.com/bnfinet/lasso/pkg/cfg" + "github.com/LassoProject/lasso/pkg/cfg" log "github.com/Sirupsen/logrus" "github.com/boltdb/bolt" ) diff --git a/pkg/model/model_test.go b/pkg/model/model_test.go index 663ffa4a..a56a382b 100644 --- a/pkg/model/model_test.go +++ b/pkg/model/model_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/structs" ) var testdb = "/tmp/storage-test.db" diff --git a/pkg/model/site.go b/pkg/model/site.go index 9b43da6c..3b149924 100644 --- a/pkg/model/site.go +++ b/pkg/model/site.go @@ -6,7 +6,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/structs" "github.com/boltdb/bolt" ) diff --git a/pkg/model/team.go b/pkg/model/team.go index 1a378633..eccbd93c 100644 --- a/pkg/model/team.go +++ b/pkg/model/team.go @@ -7,7 +7,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/structs" "github.com/boltdb/bolt" ) diff --git a/pkg/model/user.go b/pkg/model/user.go index 3ed3730f..06897c22 100644 --- a/pkg/model/user.go +++ b/pkg/model/user.go @@ -7,7 +7,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/structs" "github.com/boltdb/bolt" ) diff --git a/pkg/timelog/timelog.go b/pkg/timelog/timelog.go index 65ce51dd..8c149b65 100644 --- a/pkg/timelog/timelog.go +++ b/pkg/timelog/timelog.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - lctx "github.com/bnfinet/lasso/pkg/context" + lctx "github.com/LassoProject/lasso/pkg/context" log "github.com/Sirupsen/logrus" // "github.com/mattn/go-isatty" diff --git a/pkg/transciever/client.go b/pkg/transciever/client.go index 944ed28b..dd396a43 100644 --- a/pkg/transciever/client.go +++ b/pkg/transciever/client.go @@ -6,8 +6,8 @@ import ( "net/http" "time" - "github.com/bnfinet/lasso/pkg/model" - "github.com/bnfinet/lasso/pkg/structs" + "github.com/LassoProject/lasso/pkg/model" + "github.com/LassoProject/lasso/pkg/structs" log "github.com/Sirupsen/logrus" "github.com/mitchellh/mapstructure" From fbe82227dbc429331339e21468f4d72ff50feb7f Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 17 Aug 2018 14:45:10 -0400 Subject: [PATCH 017/736] add empty data folder --- data/.gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/.gitignore diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 00000000..e69de29b From 5a3b2261c4476e0566dcc86ffd05bdc1e554014d Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 17 Aug 2018 14:49:03 -0400 Subject: [PATCH 018/736] update config example for readability --- config/config.yml_example | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index 5611abf4..013af8ce 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -4,23 +4,28 @@ lasso: logLevel: info listen: 0.0.0.0 port: 9090 + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider allowAllUsers: false + # Setting publicAccess: true will accept all requests, even without a cookie. # If the user is logged in, the cookie will be validated and the user header will be set. # You will need to direct people to the Lasso login page from your application. publicAccess: false + # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... # usually you'll just have one. # Comment this out if you set allowAllUser:true domains: - yourdomain.com - yourotherdomain.com + jwt: issuer: Lasso maxAge: 240 secret: your_random_string compress: true + cookie: # name of cookie to store the jwt name: Lasso-cookie @@ -28,14 +33,18 @@ lasso: # domain: yourdomain.com secure: true httpOnly: true + + session: + name: lasso-session + headers: jwt: X-Lasso-Token querystring: access_token redirect: X-Lasso-Requested-URI + db: file: data/lasso_bolt.db - session: - name: lasso-session + test_url: http://yourdomain.com # @@ -50,7 +59,6 @@ oauth: # https://console.developers.google.com/apis/credentials client_id: client_secret: - # must be the /auth endpoint callback_urls: - http://lasso.yourdomain.com:9090/auth - http://lasso.yourotherdomain.com:9090/auth @@ -64,6 +72,7 @@ oauth: auth_url: https://github.com/login/oauth/authorize token_url: https://github.com/login/oauth/access_token # callback_url is configured at github.com when setting up the app + # set to e.g. https://lasso.yourdomain.com/auth scopes: - user user_info_url: https://api.github.com/user?access_token= From 97e07554088696fdf693c367a5d58e8fd0a84600 Mon Sep 17 00:00:00 2001 From: Qingsong Yao Date: Fri, 21 Sep 2018 14:07:53 -0700 Subject: [PATCH 019/736] use genOauth.UserInfoURL if it is set --- handlers/handlers.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 49fffee4..1a65831a 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -496,7 +496,11 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) - userinfo, err := client.Get("https://api.github.com/user?access_token=" + ptoken.AccessToken) + userInfoUrl := "https://api.github.com/user?access_token=" + if genOauth.UserInfoURL != "" { + userInfoUrl = genOauth.UserInfoURL + } + userinfo, err := client.Get(userInfoUrl + ptoken.AccessToken) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) return err From 6df322210e0d507b9e85c25d2aab8c7c24523d84 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 24 Sep 2018 13:10:49 -0700 Subject: [PATCH 020/736] aaron indieauth TODOs --- TODO.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/TODO.md b/TODO.md index 579f89b8..c04a1471 100644 --- a/TODO.md +++ b/TODO.md @@ -5,15 +5,43 @@ ## TODO +* aaronpk 2017-10-04 + ‎[15:46] ‎<‎aaronpk‎>‎ so, immediate feature request is to be able to whitelist specific email addresses instead of doing domain matching for users + + +* aaronpk + ‎[16:40] ‎<‎aaronpk‎>‎ sure! basically i want to redirect to https://indieauth.com instead of google auth + ‎[16:41] ‎<‎aaronpk‎>‎ and there's an endpoint there that the plugin can use to verify the auth code and get user info + ‎[16:44] ‎<‎aaronpk‎>‎ so being able to customize this URL or maybe even override some method to be ableto customize the handling of the verification https://github.com/bnfinet/lasso/blob/master/handlers/handlers.go#L313 + ‎[16:49] ‎<‎aaronpk‎>‎ here's the docs i was walking you through https://indieauth.com/developers + ‎[16:53] ‎<‎bfoote‎>‎ oh that's looks pretty straight forward + +* add config for oauth Enpoint + https://github.com/golang/oauth2/blob/master/github/github.go + if endpoing is ~= google then allow 'hd' and accomodate getting User info + * is user info for Oauth a standard form? Probably _no_. Going to need some interpreters. + * create a special team for admins * look for the token in an "Authorization: bearer $TOKEN" header +* include static assets in binary + https://github.com/shurcooL/vfsgen + * restapi * `/api/validate` endpoint that *any* service can connect to that validates the `X-LASSO-TOKEN` header * add lastupdate to user, sites, team +* handle multiple domains + * set the `Oauth2.config{RedirectURL}` Google callback URL dynamically based on the domain that was offered + + +* iterate through a list of authorized domains + * 302 redirect to the next domain + * set a jwt cookie into each domain + * might slow down login + * how to handle "not authorized for domain"? * can nginx pass a 302 back to /login with an argument in the querystring such as.. /login?jwt=$COOKIE @@ -60,6 +88,9 @@ ## DONE +* set X-Lasso-User header passed through to the backend app + https://stackoverflow.com/questions/19366215/setting-headers-with-nginx-auth-request-proxy#19366411 + * replace gin.Cookie with gorilla.cookie * optionally compress the cookie (gzip && base64) From 1b874f2b5cab8911628b5f8230d1bc39b1e28377 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 24 Sep 2018 13:14:26 -0700 Subject: [PATCH 021/736] minor case and syntax changes --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 414a2e1e..3aaee2a1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Lasso -an SSO solution for an nginx reverse proxy using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module +an SSO solution for nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module -lasso supports oauth for google apps, [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) and [indieauth](https://indieauth.com/developers) +lasso supports OAuth login to google apps, [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) and [indieauth](https://indieauth.com/developers) If lasso is running on the same host as the nginx reverse proxy the response time from the `/validate` endpoint to nginx should be less than 1ms @@ -82,7 +82,8 @@ And that's it! Or if you can examine the docker command in `do.sh` The [bfoote/lasso](https://hub.docker.com/r/bfoote/lasso/) Docker image is an automated build on Docker Hub ## Running from source -``` + +```bash go get ./... go build ./lasso @@ -106,7 +107,7 @@ The [bfoote/lasso](https://hub.docker.com/r/bfoote/lasso/) Docker image is an au * if the cookie is found, and the JWT is valid * returns 200 to nginx, which will allow access (bob notices nothing) * if the cookie is NOT found, or the JWT is NOT valid - * return 401 NotAuthorized to nginx (which forwards the request on to login) + * return 401 NotAuthorized to nginx (which forwards the request on to login) * Bob is first forwarded briefly to `https://lasso.oursites.com/login?url=https://private.oursites.com` * clears out the cookie named "oursitesSSO" if it exists From 7a1c81cb32560522cae06f47de03e97b6e92a01f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 24 Sep 2018 13:18:20 -0700 Subject: [PATCH 022/736] delete team --- pkg/model/model_test.go | 11 ++++++++++- pkg/model/team.go | 20 +++++++++++++++++--- pkg/transciever/client.go | 17 +++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/pkg/model/model_test.go b/pkg/model/model_test.go index 663ffa4a..67bd3402 100644 --- a/pkg/model/model_test.go +++ b/pkg/model/model_test.go @@ -71,12 +71,13 @@ func TestPutSiteGetSite(t *testing.T) { assert.Equal(t, s1.Domain, s2.Domain) } -func TestPutTeamGetTeam(t *testing.T) { +func TestPutTeamGetTeamDeleteTeam(t *testing.T) { os.Remove(testdb) Open(testdb) t1 := structs.Team{Name: "testname"} t2 := &structs.Team{} + t3 := &structs.Team{} if err := PutTeam(t1); err != nil { log.Error(err) @@ -84,4 +85,12 @@ func TestPutTeamGetTeam(t *testing.T) { Team([]byte(t1.Name), t2) log.Debugf("team retrieved: %v", *t2) assert.Equal(t, t1.Name, t2.Name) + + if err := DeleteTeam(t1); err != nil { + log.Error(err) + } + // should fail + err := Team([]byte(t1.Name), t3) + assert.Error(t, err) + } diff --git a/pkg/model/team.go b/pkg/model/team.go index 1a378633..b69851c6 100644 --- a/pkg/model/team.go +++ b/pkg/model/team.go @@ -11,10 +11,10 @@ import ( "github.com/boltdb/bolt" ) -// PutTeam inna da db +// PutTeam - create or update a team func PutTeam(t structs.Team) error { teamexists := false - curt := &structs.Team{} + curt := &structs.Team{} // curt == current team err := Team([]byte(t.Name), curt) if err == nil { teamexists = true @@ -26,7 +26,7 @@ func PutTeam(t structs.Team) error { if b := getBucket(tx, teamBucket); b != nil { t.LastUpdate = time.Now().Unix() if teamexists { - log.Debugf("teamexists.. keeping time at %v", curt.CreatedOn) + log.Debugf("teamexists.. keeping time at %v, members are %v", curt.CreatedOn, curt.Members) t.CreatedOn = curt.CreatedOn } else { id, _ := b.NextSequence() @@ -66,6 +66,20 @@ func Team(key []byte, t *structs.Team) error { }) } +// DeleteTeam from key +func DeleteTeam(t structs.Team) error { + return Db.Update(func(tx *bolt.Tx) error { + if b := tx.Bucket(teamBucket); b != nil { + if err := b.Delete([]byte(t.Name)); err != nil { + return err + } + log.Debugf("deleted %s from db", t.Name) + return nil + } + return fmt.Errorf("no bucket for %s", teamBucket) + }) +} + // AllTeams collect all items func AllTeams(teams *[]structs.Team) error { return Db.View(func(tx *bolt.Tx) error { diff --git a/pkg/transciever/client.go b/pkg/transciever/client.go index 944ed28b..fb4a8d55 100644 --- a/pkg/transciever/client.go +++ b/pkg/transciever/client.go @@ -100,6 +100,8 @@ func (c *Client) readPump() { c.shipTeams() } else if p.T == "updateteam" { c.updateTeam(p.D) + } else if p.T == "deleteteam" { + c.deleteTeam(p.D) } // c.hub.broadcast <- []byte(p) } @@ -118,6 +120,21 @@ func (c *Client) updateTeam(data interface{}) { c.shipTeams() } +func (c *Client) deleteTeam(data interface{}) { + + t := structs.Team{} + mapstructure.Decode(data, &t) + log.Debugf("deleting team %v", t) + model.DeleteTeam(t) + testT := structs.Team{} + if err := model.Team([]byte(t.Name), &testT); err != nil { + log.Error(err) + } + log.Debugf("if deleted should be null: %s", testT.Name) + + c.shipTeams() +} + // writePump pumps messages from the hub to the websocket connection. // // A goroutine running writePump is started for each connection. The From 13d8a8c74e4f3a9239a722f59d3132c7e2785150 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 24 Sep 2018 13:19:29 -0700 Subject: [PATCH 023/736] AUTHORS initial commit --- AUTHORS.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 AUTHORS.txt diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 00000000..8f5d90ad --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,2 @@ +bnfinet +aaronpk \ No newline at end of file From 23ee5374c7a00f591889ac22c1d1a6412de5bfad Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sun, 30 Sep 2018 16:21:00 -0700 Subject: [PATCH 024/736] make note about $auth_resp_x_lasso_user in `location /` as per #26 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3aaee2a1..52fe57ed 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ server { # send all requests to the `/validate` endpoint for authorization auth_request /validate; - # if validate returns `401 not authorized` then forward the request to the error401block + # if validate returns `401 not authorized` then forward the request to the error401block error_page 401 = @error401; location = /validate { From 0d1b5ba9093d46edce4d58b0857fbdbbeccc5613 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 11:17:23 -0700 Subject: [PATCH 025/736] add cookie explanation --- config/config.yml_example | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.yml_example b/config/config.yml_example index 013af8ce..06dddcb9 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -14,6 +14,7 @@ lasso: publicAccess: false # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... + # so that the cookie which stores the JWT can be set in the relevant domain # usually you'll just have one. # Comment this out if you set allowAllUser:true domains: From bb8fac113f6786d30b39e98519d4cce6e31c93d6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 12:34:28 -0700 Subject: [PATCH 026/736] minor formatting changes --- handlers/handlers.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 1a65831a..63f4f61c 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -234,6 +234,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { // renderIndex(w, "user found from email "+user.Email) w.Header().Add("X-Lasso-User", claims.Email) + w.Header().Add("X-Lasso-Success", "true"); log.Debugf("X-Lasso-User response headers %s", w.Header().Get("X-Lasso-User")) renderIndex(w, "user found in jwt "+claims.Email) @@ -449,9 +450,8 @@ func getUserInfo(r *http.Request, user *structs.User) error { return getUserInfoFromGithub(client, user, providerToken) } else if genOauth.Provider == "oidc" { return getUserInfoFromOpenID(client, user, providerToken) - } else { - log.Error("we don't know how to look up the user info") } + log.Error("we don't know how to look up the user info") return nil } @@ -496,11 +496,11 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) - userInfoUrl := "https://api.github.com/user?access_token=" + userInfoURL := "https://api.github.com/user?access_token=" if genOauth.UserInfoURL != "" { - userInfoUrl = genOauth.UserInfoURL + userInfoURL = genOauth.UserInfoURL } - userinfo, err := client.Get(userInfoUrl + ptoken.AccessToken) + userinfo, err := client.Get(userInfoURL + ptoken.AccessToken) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) return err From c90b50832937528ef6a01579ce6c3c4de5fc6878 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 13:00:30 -0700 Subject: [PATCH 027/736] don't store lasso binary --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5941f189..02aec4ee 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ data/lasso_bolt.db pkg/model/storage-test.db main config/google_config.json -.vscode/* \ No newline at end of file +.vscode/* +lasso From f41664ec64e8fc1183bac7b5c0625b0954f785e6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 13:30:03 -0700 Subject: [PATCH 028/736] set vars in / block as per #26 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 52fe57ed..96d9e4be 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ server { # proxy pass authorized requests to your service location / { proxy_pass http://dev.yourdomain.com:8080; + # may need to set + # auth_request_set $auth_resp_x_lasso_user $upstream_http_x_lasso_user + # in this bock as per https://github.com/LassoProject/lasso/issues/26#issuecomment-425215810 # set user header (usually an email) proxy_set_header X-Lasso-User $auth_resp_x_lasso_user; } From ee0c30d0277a7e4a99c0b3b6f2761cba5aa1075f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 13:33:56 -0700 Subject: [PATCH 029/736] fix #6 log error when URL is not set and render index --- handlers/handlers.go | 42 ++++++++++++++++++++++++------------------ templates/index.tmpl | 5 +++++ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 63f4f61c..c5792288 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -277,9 +277,10 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { session.Save(r, w) sessstore.MaxAge(300) - var redirectURL = r.URL.Query().Get("url") - if redirectURL != "" { - http.Redirect(w, r, redirectURL, 302); + + var requestedURL = r.URL.Query().Get("url") + if requestedURL != "" { + http.Redirect(w, r, requestedURL, 302); } else { renderIndex(w, "you have been logged out") } @@ -297,36 +298,41 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { log.Error(err) } - // set the state varialbe in the session + // set the state variable in the session var state = randString() session.Values["state"] = state log.Debugf("session state set to %s", session.Values["state"]) // increment the failure counter for this domain - // redirectURL comes from nginx in the query string - var redirectURL = r.URL.Query().Get("url") - if redirectURL != "" { - // TODO store the originally requested URL so we can redirec on the roundtrip - session.Values["requestedURL"] = redirectURL + // requestedURL comes from nginx in the query string via a 302 redirect + // it sets the ultimate destination + // https://lasso.yoursite.com/login?url= + var requestedURL = r.URL.Query().Get("url"); + if (requestedURL == "") { + renderIndex(w, "no destination URL requested") + log.Error("no destination URL requested") + return + } else { + session.Values["requestedURL"] = requestedURL log.Debugf("session requestedURL set to %s", session.Values["requestedURL"]) } // stop them after three failures for this URL var failcount = 0 - if session.Values[redirectURL] != nil { - failcount = session.Values[redirectURL].(int) - log.Debugf("failcount for %s is %d", redirectURL, failcount) + if session.Values[requestedURL] != nil { + failcount = session.Values[requestedURL].(int) + log.Debugf("failcount for %s is %d", requestedURL, failcount) } failcount++ - session.Values[redirectURL] = failcount + session.Values[requestedURL] = failcount log.Debug("saving session") session.Save(r, w) if failcount > 2 { var lassoError = r.URL.Query().Get("error") - renderIndex(w, "too many redirects for "+redirectURL+" - "+lassoError) + renderIndex(w, "too many redirects for "+requestedURL+" - "+lassoError) } else { // bounce to oauth provider for login var lURL = loginURL(r, state) @@ -412,16 +418,16 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { cookie.SetCookie(w, r, tokenstring) // get the originally requested URL so we can send them on their way - redirectURL := session.Values["requestedURL"].(string) - if redirectURL != "" { + requestedURL := session.Values["requestedURL"].(string) + if requestedURL != "" { // clear out the session value session.Values["requestedURL"] = "" - session.Values[redirectURL] = 0 + session.Values[requestedURL] = 0 session.Save(r, w) // and redirect context.WithValue(r.Context(), lctx.StatusCode, 302) - http.Redirect(w, r, redirectURL, 302) + http.Redirect(w, r, requestedURL, 302) return } // otherwise serve an html page diff --git a/templates/index.tmpl b/templates/index.tmpl index 12502c6d..ecfcf43b 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -3,6 +3,7 @@ + Lasso: {{ .Msg }}. @@ -15,5 +16,9 @@
  • {{ .TestURL }}
  • +For support, please contact your network administrator or whomever setup nginx to use Lasso. +

    +For help with Lasso or to file a bug report, please see the project page at https://github.com/LassoProject/lasso +

    From 5162350774150a422607b6d8f61a9b119f2517c8 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 14:34:31 -0700 Subject: [PATCH 030/736] fix #13 test for required config options, and panic if they're not there --- pkg/cfg/cfg.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 41b90e24..f1b8adec 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -1,6 +1,7 @@ package cfg import ( + "errors" "flag" "os" @@ -46,8 +47,8 @@ type CfgT struct { // Cfg the main exported config variable var Cfg CfgT -// V viper object -// var V viper +// RequiredOptions must have these fields set for minimum viable config +var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.domains", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id", "oauth.client_secret"} func init() { ParseConfig() @@ -72,6 +73,11 @@ func ParseConfig() { panic(err) } UnmarshalKey("lasso", &Cfg) + errT := BasicTest() + if errT != nil { + // log.Fatalf(err.prob) + panic(errT) + } // nested defaults is currently *broken* // https://github.com/spf13/viper/issues/309 // viper.SetDefault("listen", "0.0.0.0") @@ -91,3 +97,13 @@ func UnmarshalKey(key string, rawVal interface{}) error { func Get(key string) string { return viper.GetString(key) } + +// BasicTest just a quick sanity check to see if the config is sound +func BasicTest() error { + for _, opt := range RequiredOptions { + if (!viper.IsSet(opt)) { + return errors.New("configuration option " + opt + " is not set in config") + } + } + return nil +} \ No newline at end of file From a8edac3a79f97d27c43857afaa1c1777f09ce346 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 15:39:56 -0700 Subject: [PATCH 031/736] don't require lasso.domains --- pkg/cfg/cfg.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index f1b8adec..44c23480 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -31,9 +31,9 @@ type CfgT struct { HTTPOnly bool `mapstructure:"httpOnly"` } Headers struct { - JWT string `mapstructure:"jwt"` + JWT string `mapstructure:"jwt"` QueryString string `mapstructure:"querystring"` - Redirect string `mapstructure:"redirect"` + Redirect string `mapstructure:"redirect"` } DB struct { File string `mapstructure:"file"` @@ -48,7 +48,7 @@ type CfgT struct { var Cfg CfgT // RequiredOptions must have these fields set for minimum viable config -var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.domains", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id", "oauth.client_secret"} +var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id", "oauth.client_secret"} func init() { ParseConfig() @@ -101,9 +101,9 @@ func Get(key string) string { // BasicTest just a quick sanity check to see if the config is sound func BasicTest() error { for _, opt := range RequiredOptions { - if (!viper.IsSet(opt)) { + if !viper.IsSet(opt) { return errors.New("configuration option " + opt + " is not set in config") } } return nil -} \ No newline at end of file +} From d7b3106bd6c55abd5cb69365adc89935389a1d5e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 2 Oct 2018 16:25:12 -0700 Subject: [PATCH 032/736] use ghUser and set User.email from ghUser.login --- handlers/handlers.go | 34 ++++++++++++++++++++++------------ pkg/structs/structs.go | 20 +++++++++++--------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index c5792288..26a89159 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -195,7 +195,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{Error: "no jwt found"}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -206,7 +206,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{err.Error(), jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -215,7 +215,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"no email found in jwt", jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -226,7 +226,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -234,7 +234,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { // renderIndex(w, "user found from email "+user.Email) w.Header().Add("X-Lasso-User", claims.Email) - w.Header().Add("X-Lasso-Success", "true"); + w.Header().Add("X-Lasso-Success", "true") log.Debugf("X-Lasso-User response headers %s", w.Header().Get("X-Lasso-User")) renderIndex(w, "user found in jwt "+claims.Email) @@ -277,10 +277,9 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { session.Save(r, w) sessstore.MaxAge(300) - var requestedURL = r.URL.Query().Get("url") if requestedURL != "" { - http.Redirect(w, r, requestedURL, 302); + http.Redirect(w, r, requestedURL, 302) } else { renderIndex(w, "you have been logged out") } @@ -308,8 +307,8 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // requestedURL comes from nginx in the query string via a 302 redirect // it sets the ultimate destination // https://lasso.yoursite.com/login?url= - var requestedURL = r.URL.Query().Get("url"); - if (requestedURL == "") { + var requestedURL = r.URL.Query().Get("url") + if requestedURL == "" { renderIndex(w, "no destination URL requested") log.Error("no destination URL requested") return @@ -359,7 +358,10 @@ func VerifyUser(u interface{}) (ok bool, err error) { // TODO: how do we manage the user? user := u.(structs.User) - if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { + if cfg.Cfg.AllowAllUsers { + ok = true + // if we're not allowing all users, and we have domains configured and this email isn't in one of those domains... + } else if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { err = fmt.Errorf("Email %s is not within a lasso managed domain", user.Email) // } else if !domains.IsUnderManagement(user.HostDomain) { // err = fmt.Errorf("HostDomain %s is not within a lasso managed domain", u.HostDomain) @@ -371,7 +373,7 @@ func VerifyUser(u interface{}) (ok bool, err error) { } // CallbackHandler /auth -// - validate info from Google +// - validate info from oauth provider (Google, Github, OIDC, etc) // - create user // - issue jwt in the form of a cookie func CallbackHandler(w http.ResponseWriter, r *http.Request) { @@ -514,12 +516,20 @@ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oaut defer userinfo.Body.Close() data, _ := ioutil.ReadAll(userinfo.Body) log.Println("github userinfo body: ", string(data)) - if err = json.Unmarshal(data, user); err != nil { + ghUser := &structs.GithubUser{} + if err = json.Unmarshal(data, ghUser); err != nil { + // if err = json.Unmarshal(data, user); err != nil { log.Errorln(err) // renderIndex(w, "Error marshalling response. Please try agian.") // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } + ghUser.Email = ghUser.Login + if ghUser.Email == "" && ghUser.Login != "" { + log.Debug("no email returned from github, setting user email to login " + ghUser.Login) + } + user = &ghUser.User + log.Debug("getUserInfoFromGithub") log.Debug(user) return nil } diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 43f957c0..1f6856ae 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -11,6 +11,7 @@ type User struct { } // GoogleUser is a retrieved and authentiacted user from Google. +// unused! type GoogleUser struct { User Sub string `json:"sub"` @@ -27,22 +28,23 @@ type GoogleUser struct { // GithubUser is a retrieved and authentiacted user from Github. type GithubUser struct { User + Login string `json:"login"` Picture string `json:"avatar_url"` // jwt.StandardClaims } // GenericOauth provides endoint for access type GenericOauth struct { - ClientID string `mapstructure:"client_id"` - ClientSecret string `mapstructure:"client_secret"` - AuthURL string `mapstructure:"auth_url"` - TokenURL string `mapstructure:"token_url"` - RedirectURL string `mapstructure:"callback_url"` + ClientID string `mapstructure:"client_id"` + ClientSecret string `mapstructure:"client_secret"` + AuthURL string `mapstructure:"auth_url"` + TokenURL string `mapstructure:"token_url"` + RedirectURL string `mapstructure:"callback_url"` RedirectURLs []string `mapstructure:"callback_urls"` - Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url"` - Provider string `mapstructure:"provider"` - PreferredDomain string `mapstructre:"preferredDomain"` + Scopes []string `mapstructure:"scopes"` + UserInfoURL string `mapstructure:"user_info_url"` + Provider string `mapstructure:"provider"` + PreferredDomain string `mapstructre:"preferredDomain"` } // Team has members and provides acess to sites From 71f94e54014230e6c92898ff3922a13716f94ae9 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 3 Oct 2018 12:12:56 -0700 Subject: [PATCH 033/736] if testing capture 302 redirects --- handlers/handlers.go | 30 +++++++++++++++++++----------- pkg/cfg/cfg.go | 1 + 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index c5792288..27cf6148 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -195,7 +195,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{Error: "no jwt found"}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -206,7 +206,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{err.Error(), jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -215,7 +215,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"no email found in jwt", jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -226,7 +226,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) } else { - w.Header().Add("X-Lasso-User", ""); + w.Header().Add("X-Lasso-User", "") } return } @@ -234,7 +234,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { // renderIndex(w, "user found from email "+user.Email) w.Header().Add("X-Lasso-User", claims.Email) - w.Header().Add("X-Lasso-Success", "true"); + w.Header().Add("X-Lasso-Success", "true") log.Debugf("X-Lasso-User response headers %s", w.Header().Get("X-Lasso-User")) renderIndex(w, "user found in jwt "+claims.Email) @@ -277,10 +277,9 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { session.Save(r, w) sessstore.MaxAge(300) - var requestedURL = r.URL.Query().Get("url") if requestedURL != "" { - http.Redirect(w, r, requestedURL, 302); + redirect302(w, r, requestedURL) } else { renderIndex(w, "you have been logged out") } @@ -308,8 +307,8 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // requestedURL comes from nginx in the query string via a 302 redirect // it sets the ultimate destination // https://lasso.yoursite.com/login?url= - var requestedURL = r.URL.Query().Get("url"); - if (requestedURL == "") { + var requestedURL = r.URL.Query().Get("url") + if requestedURL == "" { renderIndex(w, "no destination URL requested") log.Error("no destination URL requested") return @@ -338,7 +337,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { var lURL = loginURL(r, state) log.Debugf("redirecting to oauthURL %s", lURL) context.WithValue(r.Context(), lctx.StatusCode, 302) - http.Redirect(w, r, lURL, 302) + redirect302(w, r, lURL) } } @@ -427,7 +426,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { // and redirect context.WithValue(r.Context(), lctx.StatusCode, 302) - http.Redirect(w, r, requestedURL, 302) + redirect302(w, r, requestedURL) return } // otherwise serve an html page @@ -585,3 +584,12 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { log.Debug(user) return nil } + +func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { + if cfg.Cfg.Testing { + cfg.Cfg.TestURL = rURL + renderIndex(w, "302 redirect to: "+cfg.Cfg.TestURL) + return + } + http.Redirect(w, r, rURL, 302) +} diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 44c23480..1fe61b1f 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -42,6 +42,7 @@ type CfgT struct { Name string `mapstructure:"name"` } TestURL string `mapstructure:"test_url"` + Testing bool `mapstructure:"testing"` } // Cfg the main exported config variable From 7b4e133e60fa84a6c1f6aa118bb98a0130825f7d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 3 Oct 2018 12:17:35 -0700 Subject: [PATCH 034/736] fix merge conflict --- handlers/handlers.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 26a89159..7b79e2f1 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -279,7 +279,7 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { var requestedURL = r.URL.Query().Get("url") if requestedURL != "" { - http.Redirect(w, r, requestedURL, 302) + redirect302(w, r, requestedURL) } else { renderIndex(w, "you have been logged out") } @@ -337,7 +337,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { var lURL = loginURL(r, state) log.Debugf("redirecting to oauthURL %s", lURL) context.WithValue(r.Context(), lctx.StatusCode, 302) - http.Redirect(w, r, lURL, 302) + redirect302(w, r, lURL) } } @@ -429,7 +429,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { // and redirect context.WithValue(r.Context(), lctx.StatusCode, 302) - http.Redirect(w, r, requestedURL, 302) + redirect302(w, r, requestedURL) return } // otherwise serve an html page @@ -595,3 +595,12 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { log.Debug(user) return nil } + +func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { + if cfg.Cfg.Testing { + cfg.Cfg.TestURL = rURL + renderIndex(w, "302 redirect to: "+cfg.Cfg.TestURL) + return + } + http.Redirect(w, r, rURL, 302) +} From 0b922df2aea4d0199aadd9a445b8900633f292c2 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 8 Oct 2018 17:20:01 -0700 Subject: [PATCH 035/736] ticket #16 add Username as identifier and populate accordingly --- handlers/handlers.go | 67 +++++++++++++++++++++--------------- pkg/jwtmanager/jwtmanager.go | 19 +++++----- pkg/structs/structs.go | 22 ++++++++++++ 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 7b79e2f1..c3e01c20 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -210,16 +210,16 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } return } - if claims.Email == "" { + if claims.Username == "" { // no email in jwt if !cfg.Cfg.PublicAccess { - error401(w, r, AuthError{"no email found in jwt", jwt}) + error401(w, r, AuthError{"no Username found in jwt", jwt}) } else { w.Header().Add("X-Lasso-User", "") } return } - log.Infof("email from jwt cookie: %s", claims.Email) + log.Infof("email from jwt cookie: %s", claims.Username) if !cfg.Cfg.AllowAllUsers { if !jwtmanager.SiteInClaims(r.Host, &claims) { @@ -233,10 +233,10 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } // renderIndex(w, "user found from email "+user.Email) - w.Header().Add("X-Lasso-User", claims.Email) + w.Header().Add("X-Lasso-User", claims.Username) w.Header().Add("X-Lasso-Success", "true") log.Debugf("X-Lasso-User response headers %s", w.Header().Get("X-Lasso-User")) - renderIndex(w, "user found in jwt "+claims.Email) + renderIndex(w, "/validate user found in jwt "+claims.Username) // TODO // parse the jwt and see if the claim is valid for the domain @@ -281,7 +281,7 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { if requestedURL != "" { redirect302(w, r, requestedURL) } else { - renderIndex(w, "you have been logged out") + renderIndex(w, "/logout you have been logged out") } } @@ -309,14 +309,15 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // https://lasso.yoursite.com/login?url= var requestedURL = r.URL.Query().Get("url") if requestedURL == "" { - renderIndex(w, "no destination URL requested") + renderIndex(w, "/login no destination URL requested") log.Error("no destination URL requested") return - } else { - session.Values["requestedURL"] = requestedURL - log.Debugf("session requestedURL set to %s", session.Values["requestedURL"]) } + // set session variable for eventual 302 redirecton to orginal request + session.Values["requestedURL"] = requestedURL + log.Debugf("session requestedURL set to %s", session.Values["requestedURL"]) + // stop them after three failures for this URL var failcount = 0 if session.Values[requestedURL] != nil { @@ -331,7 +332,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { if failcount > 2 { var lassoError = r.URL.Query().Get("error") - renderIndex(w, "too many redirects for "+requestedURL+" - "+lassoError) + renderIndex(w, "/login too many redirects for "+requestedURL+" - "+lassoError) } else { // bounce to oauth provider for login var lURL = loginURL(r, state) @@ -360,14 +361,15 @@ func VerifyUser(u interface{}) (ok bool, err error) { if cfg.Cfg.AllowAllUsers { ok = true + log.Debugf("skipping verify user since cfg.Cfg.AllowAllUsers is %t", cfg.Cfg.AllowAllUsers) // if we're not allowing all users, and we have domains configured and this email isn't in one of those domains... } else if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { err = fmt.Errorf("Email %s is not within a lasso managed domain", user.Email) // } else if !domains.IsUnderManagement(user.HostDomain) { // err = fmt.Errorf("HostDomain %s is not within a lasso managed domain", u.HostDomain) } else { - log.Debugf("no domains configured") ok = true + log.Debug("no domains configured") } return ok, err } @@ -391,22 +393,22 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { queryState := r.URL.Query().Get("state") if session.Values["state"] != queryState { log.Errorf("Invalid session state: stored %s, returned %s", session.Values["state"], queryState) - renderIndex(w, "Invalid session state.") + renderIndex(w, "/auth Invalid session state.") return } user := structs.User{} - if err := getUserInfo(r, &user); err != nil { log.Error(err) http.Error(w, err.Error(), http.StatusBadRequest) return } + log.Debug("CallbackHandler") log.Debug(user) if ok, err := VerifyUser(user); !ok { log.Error(err) - renderIndex(w, fmt.Sprintf("User is not authorized. %s Please try again.", err)) + renderIndex(w, fmt.Sprintf("/auth User is not authorized. %s Please try again.", err)) return } @@ -433,7 +435,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { return } // otherwise serve an html page - renderIndex(w, tokenstring) + renderIndex(w, "/auth "+tokenstring) } // TODO: put all getUserInfo logic into its own pkg @@ -478,6 +480,7 @@ func getUserInfoFromOpenID(client *http.Client, user *structs.User, ptoken *oaut // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } + user.PrepareUserData() return nil } @@ -496,6 +499,8 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } + user.PrepareUserData() + return nil } @@ -503,11 +508,13 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { // https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { - log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) + // TODO: move to cfg package userInfoURL := "https://api.github.com/user?access_token=" if genOauth.UserInfoURL != "" { userInfoURL = genOauth.UserInfoURL } + + log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) userinfo, err := client.Get(userInfoURL + ptoken.AccessToken) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) @@ -516,19 +523,23 @@ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oaut defer userinfo.Body.Close() data, _ := ioutil.ReadAll(userinfo.Body) log.Println("github userinfo body: ", string(data)) - ghUser := &structs.GithubUser{} - if err = json.Unmarshal(data, ghUser); err != nil { - // if err = json.Unmarshal(data, user); err != nil { + ghUser := structs.GithubUser{} + if err = json.Unmarshal(data, &ghUser); err != nil { log.Errorln(err) - // renderIndex(w, "Error marshalling response. Please try agian.") - // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } - ghUser.Email = ghUser.Login - if ghUser.Email == "" && ghUser.Login != "" { - log.Debug("no email returned from github, setting user email to login " + ghUser.Login) - } - user = &ghUser.User + log.Debug("getUserInfoFromGithub ghUser") + log.Debug(ghUser) + log.Debug("getUserInfoFromGithub user") + log.Debug(user) + + ghUser.PrepareUserData() + user.Email = ghUser.Email + user.Name = ghUser.Name + user.Username = ghUser.Username + user.ID = ghUser.ID + // user = &ghUser.User + log.Debug("getUserInfoFromGithub") log.Debug(user) return nil @@ -598,8 +609,10 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { if cfg.Cfg.Testing { + var tmp = cfg.Cfg.TestURL cfg.Cfg.TestURL = rURL renderIndex(w, "302 redirect to: "+cfg.Cfg.TestURL) + cfg.Cfg.TestURL = tmp return } http.Redirect(w, r, rURL, 302) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index f15ad60e..04126902 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -10,9 +10,9 @@ import ( "strings" "time" - log "github.com/Sirupsen/logrus" "github.com/LassoProject/lasso/pkg/cfg" "github.com/LassoProject/lasso/pkg/structs" + log "github.com/Sirupsen/logrus" jwt "github.com/dgrijalva/jwt-go" ) @@ -21,8 +21,8 @@ import ( // LassoClaims jwt Claims specific to lasso type LassoClaims struct { - Email string `json:"email"` - Sites []string `json:"sites"` // tempting to make this a map but the array is fewer characters in the jwt + Username string `json:"username"` + Sites []string `json:"sites"` // tempting to make this a map but the array is fewer characters in the jwt jwt.StandardClaims } @@ -46,8 +46,9 @@ func init() { // CreateUserTokenString converts user to signed jwt func CreateUserTokenString(u structs.User) string { // User`token` + // u.PrepareUserData() claims := LassoClaims{ - u.Email, + u.Username, Sites, StandardClaims, } @@ -135,8 +136,8 @@ func SiteInClaims(site string, claims *LassoClaims) bool { return false } -// TODO HERE there's something wrong with claims parsing, probably related to LassoClaims not being a pointer // PTokenClaims get all the claims +// TODO HERE there's something wrong with claims parsing, probably related to LassoClaims not being a pointer func PTokenClaims(ptoken *jwt.Token) (LassoClaims, error) { // func PTokenClaims(ptoken *jwt.Token) (LassoClaims, error) { // return ptoken.Claims, nil @@ -151,9 +152,9 @@ func PTokenClaims(ptoken *jwt.Token) (LassoClaims, error) { return *ptokenClaims, nil } -// PTokenToEmail returns the Email in the validated ptoken -func PTokenToEmail(ptoken *jwt.Token) (string, error) { - return ptoken.Claims.(*LassoClaims).Email, nil +// PTokenToUsername returns the Username in the validated ptoken +func PTokenToUsername(ptoken *jwt.Token) (string, error) { + return ptoken.Claims.(*LassoClaims).Username, nil // var ptokenClaims LassoClaims // ptokenClaims, err := PTokenClaims(ptoken) @@ -161,7 +162,7 @@ func PTokenToEmail(ptoken *jwt.Token) (string, error) { // log.Error(err) // return "", err // } - // return ptokenClaims.Email, nil + // return ptokenClaims.Username, nil } func decodeAndDecompressTokenString(encgzipss string) string { diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 1f6856ae..43eca09d 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -1,15 +1,26 @@ package structs +// UserI each *User struct must prepare the data for being placed in the JWT +type UserI interface { + PrepareUserData() +} + // User is inherited. type User struct { Name string `json:"name"` Email string `json:"email"` CreatedOn int64 `json:"createdon"` LastUpdate int64 `json:"lastupdate"` + Username string `json:"username",mapstructure:"username"` ID int `json:"id",mapstructure:"id"` // jwt.StandardClaims } +// PrepareUserData implement PersonalData interface +func (u *User) PrepareUserData() { + u.Username = u.Email +} + // GoogleUser is a retrieved and authentiacted user from Google. // unused! type GoogleUser struct { @@ -25,6 +36,11 @@ type GoogleUser struct { // jwt.StandardClaims } +// PrepareUserData implement PersonalData interface +func (u *GoogleUser) PrepareUserData() { + u.Username = u.Email +} + // GithubUser is a retrieved and authentiacted user from Github. type GithubUser struct { User @@ -33,6 +49,12 @@ type GithubUser struct { // jwt.StandardClaims } +// PrepareUserData implement PersonalData interface +func (u *GithubUser) PrepareUserData() { + // always use the u.Login as the u.Username + u.Username = u.Login +} + // GenericOauth provides endoint for access type GenericOauth struct { ClientID string `mapstructure:"client_id"` From 8a90f60e2ecc8859907904ddb0d8b0ef1b276eeb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 9 Oct 2018 12:55:23 -0700 Subject: [PATCH 036/736] #16 don't enforce oauth.client_secret config --- pkg/cfg/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 1fe61b1f..bcfa5a99 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -49,7 +49,7 @@ type CfgT struct { var Cfg CfgT // RequiredOptions must have these fields set for minimum viable config -var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id", "oauth.client_secret"} +var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id"} func init() { ParseConfig() From f69410612cfad638d73e17d645a65729c2fb408f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 9 Oct 2018 13:28:31 -0700 Subject: [PATCH 037/736] #16 call PrepareUserData to set Username --- handlers/handlers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/handlers/handlers.go b/handlers/handlers.go index c3e01c20..239ae67d 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -603,6 +603,7 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { return err } user.Email = ir.Email + user.PrepareUserData() log.Debug(user) return nil } From d296bee0ce836b628222350310ab5a8b8baab335 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 9 Oct 2018 17:14:17 -0400 Subject: [PATCH 038/736] refactor indieauth user response to match the github format both indieauth and github providers return the user identifier in the auth code exchange response --- handlers/handlers.go | 14 ++++---------- pkg/structs/structs.go | 9 +++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 239ae67d..a2ced701 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -545,12 +545,6 @@ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oaut return nil } -// indieauth -// https://indieauth.com/developers -type indieResponse struct { - Email string `json:"me"` -} - func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { code := r.URL.Query().Get("code") @@ -597,13 +591,13 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { defer userinfo.Body.Close() data, _ := ioutil.ReadAll(userinfo.Body) log.Println("indieauth userinfo body: ", string(data)) - ir := indieResponse{} - if err := json.Unmarshal(data, &ir); err != nil { + iaUser := structs.IndieAuthUser{} + if err = json.Unmarshal(data, &iaUser); err != nil { log.Errorln(err) return err } - user.Email = ir.Email - user.PrepareUserData() + iaUser.PrepareUserData() + user.Username = iaUser.Username log.Debug(user) return nil } diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 43eca09d..9014337c 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -55,6 +55,15 @@ func (u *GithubUser) PrepareUserData() { u.Username = u.Login } +type IndieAuthUser struct { + User + URL string `json:"me"` +} + +func (u *IndieAuthUser) PrepareUserData() { + u.Username = u.URL +} + // GenericOauth provides endoint for access type GenericOauth struct { ClientID string `mapstructure:"client_id"` From 47507aa48833883fb1bf9e86bb2269449958d99b Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 9 Oct 2018 17:14:40 -0400 Subject: [PATCH 039/736] move User.Username to the top of the struct Username is the canonical user identifier across providers, so move it to the top so that it's more visible --- pkg/structs/structs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 9014337c..0e59f97d 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -7,11 +7,11 @@ type UserI interface { // User is inherited. type User struct { + Username string `json:"username",mapstructure:"username"` Name string `json:"name"` Email string `json:"email"` CreatedOn int64 `json:"createdon"` LastUpdate int64 `json:"lastupdate"` - Username string `json:"username",mapstructure:"username"` ID int `json:"id",mapstructure:"id"` // jwt.StandardClaims } From d64a7ea526e4c1dce35f2c49e828143ec05eb59f Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 9 Oct 2018 17:28:47 -0400 Subject: [PATCH 040/736] override response_type=id for IndieAuth providers this avoids requesting an access token since we are just trying to authenticate, not trying to authorize. see https://indieauth.spec.indieweb.org/#authentication for details --- handlers/handlers.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handlers/handlers.go b/handlers/handlers.go index a2ced701..1ec48f98 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -107,6 +107,8 @@ func loginURL(r *http.Request, state string) string { } } url = oauthclient.AuthCodeURL(state, oauthopts) + } else if genOauth.Provider == "indieauth" { + url = oauthclient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) } else { url = oauthclient.AuthCodeURL(state) } From b44fdee26fb4ca0a264e2cb14c5432be04ea7533 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 9 Oct 2018 17:28:55 -0400 Subject: [PATCH 041/736] update readme to clarify indieauth support --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 96d9e4be..0f8aefaa 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Lasso -an SSO solution for nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module +an SSO solution for nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. -lasso supports OAuth login to google apps, [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) and [indieauth](https://indieauth.com/developers) +lasso supports OAuth login via Google, [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/), [IndieAuth](https://indieauth.spec.indieweb.org/), and OpenID Connect providers. If lasso is running on the same host as the nginx reverse proxy the response time from the `/validate` endpoint to nginx should be less than 1ms From d58710b9923dd96b28345479c894d90458c209f7 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:17:34 -0700 Subject: [PATCH 042/736] only start ws interface if configured to do such --- main.go | 6 +++++- pkg/transciever/transciever.go | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 764cb977..5330ab85 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,11 @@ func main() { // router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))) mux.Handle("/static", http.FileServer(http.Dir("./static"))) - mux.Handle("/ws", tran.WS) + if cfg.Cfg.WebApp { + log.Info("enabling websocket") + tran.ExplicitInit() + mux.Handle("/ws", tran.WS) + } // socketio := tran.NewServer() // mux.Handle("/socket.io/", cors.AllowAll(socketio)) diff --git a/pkg/transciever/transciever.go b/pkg/transciever/transciever.go index 36537db9..9925636d 100644 --- a/pkg/transciever/transciever.go +++ b/pkg/transciever/transciever.go @@ -20,9 +20,9 @@ var hh = &HubHolder{ Hub: newHub(), } -// NewHub -func init() { - log.Info("hub %v", hh.Hub) +// ExplicitInit only run init() if we're configured for such +func ExplicitInit() { + log.Debug("hub %v", hh.Hub) go hh.Hub.run() } From bf85d3159dfc293c61e92671dbf0df06ed76752c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:18:49 -0700 Subject: [PATCH 043/736] cleanup degug --- pkg/timelog/timelog.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/timelog/timelog.go b/pkg/timelog/timelog.go index 8c149b65..810e82ee 100644 --- a/pkg/timelog/timelog.go +++ b/pkg/timelog/timelog.go @@ -43,7 +43,8 @@ func TimeLog(nextHandler http.Handler) http.HandlerFunc { // var statusCode int // var statusColor string statusCode := ctx.Value(lctx.StatusCode) - log.Debugf("statuscode: %v", statusCode) + // TODO: this just doesn't seem to work, how can we get the statusCode from the context? + // log.Debugf("statuscode: %v", statusCode) if statusCode == nil { statusCode = 200 } From 92ef7a2639199d835ff2e5355c047af457796828 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:19:21 -0700 Subject: [PATCH 044/736] sort domains by length desc --- pkg/domains/domains.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/pkg/domains/domains.go b/pkg/domains/domains.go index aec4bd59..bee5a86d 100644 --- a/pkg/domains/domains.go +++ b/pkg/domains/domains.go @@ -1,19 +1,24 @@ package domains import ( + "sort" "strings" "github.com/LassoProject/lasso/pkg/cfg" log "github.com/Sirupsen/logrus" ) -// TODO sort domains by length from longest to shortest -// https://play.golang.org/p/N6GbEgBffd +var domains = cfg.Cfg.Domains + +func init() { + sort.Sort(ByLengthDesc(domains)) +} // Matches returns one of the domains we're configured for // TODO return all matches +// Matches return the first match of the func Matches(s string) string { - for i, v := range cfg.Cfg.Domains { + for i, v := range domains { log.Debugf("domain matched array value at [%d]=%v", i, v) if strings.Contains(s, v) { return v @@ -30,3 +35,19 @@ func IsUnderManagement(s string) bool { } return false } + +// ByLengthDesc sort from +// https://play.golang.org/p/N6GbEgBffd +type ByLengthDesc []string + +func (s ByLengthDesc) Len() int { + return len(s) +} +func (s ByLengthDesc) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// this differs by offing the longest first +func (s ByLengthDesc) Less(i, j int) bool { + return len(s[j]) < len(s[i]) +} From 1c458df529b3a704bf87ab8c557448644a9eb417 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:21:17 -0700 Subject: [PATCH 045/736] #23 email --> username --- pkg/model/user.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/model/user.go b/pkg/model/user.go index 06897c22..34bf44fe 100644 --- a/pkg/model/user.go +++ b/pkg/model/user.go @@ -6,8 +6,8 @@ import ( "fmt" "time" - log "github.com/Sirupsen/logrus" "github.com/LassoProject/lasso/pkg/structs" + log "github.com/Sirupsen/logrus" "github.com/boltdb/bolt" ) @@ -15,7 +15,7 @@ import ( func PutUser(u structs.User) error { userexists := false curu := &structs.User{} - err := User([]byte(u.Email), curu) + err := User([]byte(u.Username), curu) if err == nil { userexists = true } else { @@ -42,7 +42,7 @@ func PutUser(u structs.User) error { return err } - err = b.Put([]byte(u.Email), eU) + err = b.Put([]byte(u.Username), eU) if err != nil { log.Error(err) return err @@ -63,7 +63,7 @@ func User(key []byte, u *structs.User) error { return err } *u = *user - log.Debugf("retrieved %s from db", u.Email) + log.Debugf("retrieved %s from db", u.Username) return nil } return fmt.Errorf("no bucket for %s", userBucket) From 4a6fb4bb3cf4d870e62bceac1e31de524c9e5d6e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:27:56 -0700 Subject: [PATCH 046/736] fix #25 set defaults for config items --- handlers/handlers.go | 138 +++++++------------ pkg/cfg/cfg.go | 258 +++++++++++++++++++++++++++++++++-- pkg/jwtmanager/jwtmanager.go | 5 +- pkg/model/model.go | 13 +- pkg/model/model_test.go | 8 +- pkg/structs/structs.go | 32 ++--- 6 files changed, 322 insertions(+), 132 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 1ec48f98..8b2aa8ad 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -24,10 +24,10 @@ import ( "github.com/LassoProject/lasso/pkg/structs" "github.com/gorilla/sessions" "golang.org/x/oauth2" - "golang.org/x/oauth2/google" ) // Index variables passed to index.tmpl +// TODO: turn TestURL into an array of URLs to display type Index struct { Msg string TestURL string @@ -40,50 +40,16 @@ type AuthError struct { } var ( - genOauth structs.GenericOauth - oauthclient *oauth2.Config - oauthopts oauth2.AuthCodeOption + //oauthclient = cfg.OAuthClient*oauth2.Config TODO: remove // Templates with functions available to them indexTemplate = template.Must(template.ParseFiles("./templates/index.tmpl")) - - sessstore = sessions.NewCookieStore([]byte(cfg.Cfg.Session.Name)) + sessstore = sessions.NewCookieStore([]byte(cfg.Cfg.Session.Name)) ) -func init() { - log.Debug("init handlers") - - err := cfg.UnmarshalKey("oauth", &genOauth) - if err == nil { - if genOauth.Provider == "google" { - log.Info("configuring google oauth") - oauthclient = &oauth2.Config{ - ClientID: genOauth.ClientID, - ClientSecret: genOauth.ClientSecret, - Scopes: []string{ - // You have to select a scope from - // https://developers.google.com/identity/protocols/googlescopes#google_sign-in - "https://www.googleapis.com/auth/userinfo.email", - }, - Endpoint: google.Endpoint, - } - log.Infof("setting google oauth preferred login domain param 'hd' to %s", genOauth.PreferredDomain) - oauthopts = oauth2.SetAuthURLParam("hd", genOauth.PreferredDomain) - } else { - log.Info("configuring generic oauth") - oauthclient = &oauth2.Config{ - ClientID: genOauth.ClientID, - ClientSecret: genOauth.ClientSecret, - Endpoint: oauth2.Endpoint{ - AuthURL: genOauth.AuthURL, - TokenURL: genOauth.TokenURL, - }, - RedirectURL: genOauth.RedirectURL, - Scopes: genOauth.Scopes, - } - } - } -} +// func init() { +// log.Debug("handlers ") +// } func randString() string { b := make([]byte, 32) @@ -95,29 +61,29 @@ func loginURL(r *http.Request, state string) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var url = "" - if genOauth.Provider == "google" { + if cfg.GenOAuth.Provider == cfg.Providers.Google { // If the provider is Google, find a matching redirect URL to use for the client domain := domains.Matches(r.Host) log.Debugf("looking for redirect URL matching %v", domain) - for i, v := range genOauth.RedirectURLs { - log.Debugf("redirect value matched at [%d]=%v", i, v) + for i, v := range cfg.GenOAuth.RedirectURLs { if strings.Contains(v, domain) { - oauthclient.RedirectURL = v + log.Debugf("redirect value matched at [%d]=%v", i, v) + cfg.OAuthClient.RedirectURL = v break } } - url = oauthclient.AuthCodeURL(state, oauthopts) - } else if genOauth.Provider == "indieauth" { - url = oauthclient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) + url = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) + } else if cfg.GenOAuth.Provider == cfg.Providers.IndieAuth { + url = cfg.OAuthClient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) } else { - url = oauthclient.AuthCodeURL(state) + url = cfg.OAuthClient.AuthCodeURL(state) } // log.Debugf("loginUrl %s", url) return url } -// FindJWT look for JWT in Cookie, JWT Header, Authorization Header (OAuth 2 Bearer Token) +// FindJWT look for JWT in Cookie, JWT Header, Authorization Header (OAuth2 Bearer Token) // and Query String in that order func FindJWT(r *http.Request) string { jwt, err := cookie.Cookie(r) @@ -195,9 +161,9 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if jwt == "" { // If the module is configured to allow public access with no authentication, return 200 now if !cfg.Cfg.PublicAccess { - error401(w, r, AuthError{Error: "no jwt found"}) + error401(w, r, AuthError{Error: "no jwt found in request for "}) } else { - w.Header().Add("X-Lasso-User", "") + w.Header().Add(cfg.Cfg.Headers.User, "") } return } @@ -208,7 +174,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{err.Error(), jwt}) } else { - w.Header().Add("X-Lasso-User", "") + w.Header().Add(cfg.Cfg.Headers.User, "") } return } @@ -217,27 +183,27 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"no Username found in jwt", jwt}) } else { - w.Header().Add("X-Lasso-User", "") + w.Header().Add(cfg.Cfg.Headers.User, "") } return } - log.Infof("email from jwt cookie: %s", claims.Username) + log.Infof("username from jwt cookie: %s", claims.Username) if !cfg.Cfg.AllowAllUsers { if !jwtmanager.SiteInClaims(r.Host, &claims) { if !cfg.Cfg.PublicAccess { error401(w, r, AuthError{"not authorized for " + r.Host, jwt}) } else { - w.Header().Add("X-Lasso-User", "") + w.Header().Add(cfg.Cfg.Headers.User, "") } return } } // renderIndex(w, "user found from email "+user.Email) - w.Header().Add("X-Lasso-User", claims.Username) - w.Header().Add("X-Lasso-Success", "true") - log.Debugf("X-Lasso-User response headers %s", w.Header().Get("X-Lasso-User")) + w.Header().Add(cfg.Cfg.Headers.User, claims.Username) + w.Header().Add(cfg.Cfg.Headers.Success, "true") + log.Debugf("response header "+cfg.Cfg.Headers.User+": %s", w.Header().Get(cfg.Cfg.Headers.User)) renderIndex(w, "/validate user found in jwt "+claims.Username) // TODO @@ -377,7 +343,7 @@ func VerifyUser(u interface{}) (ok bool, err error) { } // CallbackHandler /auth -// - validate info from oauth provider (Google, Github, OIDC, etc) +// - validate info from oauth provider (Google, GitHub, OIDC, etc) // - create user // - issue jwt in the form of a cookie func CallbackHandler(w http.ResponseWriter, r *http.Request) { @@ -445,22 +411,22 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { func getUserInfo(r *http.Request, user *structs.User) error { // indieauth sends the "me" setting in json back to the callback, so just pluck it from the callback - if genOauth.Provider == "indieauth" { + if cfg.GenOAuth.Provider == "indieauth" { return getUserInfoFromIndieAuth(r, user) } - providerToken, err := oauthclient.Exchange(oauth2.NoContext, r.URL.Query().Get("code")) + providerToken, err := cfg.OAuthClient.Exchange(oauth2.NoContext, r.URL.Query().Get("code")) if err != nil { return err } // make the "third leg" request back to google to exchange the token for the userinfo - client := oauthclient.Client(oauth2.NoContext, providerToken) - if genOauth.Provider == "google" { + client := cfg.OAuthClient.Client(oauth2.NoContext, providerToken) + if cfg.GenOAuth.Provider == cfg.Providers.Google { return getUserInfoFromGoogle(client, user) - } else if genOauth.Provider == "github" { - return getUserInfoFromGithub(client, user, providerToken) - } else if genOauth.Provider == "oidc" { + } else if cfg.GenOAuth.Provider == cfg.Providers.GitHub { + return getUserInfoFromGitHub(client, user, providerToken) + } else if cfg.GenOAuth.Provider == cfg.Providers.OIDC { return getUserInfoFromOpenID(client, user, providerToken) } log.Error("we don't know how to look up the user info") @@ -468,9 +434,8 @@ func getUserInfo(r *http.Request, user *structs.User) error { } func getUserInfoFromOpenID(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { - userinfo, err := client.Get(genOauth.UserInfoURL) + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) if err != nil { - // http.Error(w, err.Error(), http.StatusBadRequest) return err } defer userinfo.Body.Close() @@ -478,8 +443,6 @@ func getUserInfoFromOpenID(client *http.Client, user *structs.User, ptoken *oaut log.Println("OpenID userinfo body: ", string(data)) if err = json.Unmarshal(data, user); err != nil { log.Errorln(err) - // renderIndex(w, "Error marshalling response. Please try agian.") - // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } user.PrepareUserData() @@ -487,9 +450,8 @@ func getUserInfoFromOpenID(client *http.Client, user *structs.User, ptoken *oaut } func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { - userinfo, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo") + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) if err != nil { - // http.Error(w, err.Error(), http.StatusBadRequest) return err } defer userinfo.Body.Close() @@ -497,8 +459,6 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { log.Println("google userinfo body: ", string(data)) if err = json.Unmarshal(data, user); err != nil { log.Errorln(err) - // renderIndex(w, "Error marshalling response. Please try agian.") - // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": }) return err } user.PrepareUserData() @@ -508,16 +468,10 @@ func getUserInfoFromGoogle(client *http.Client, user *structs.User) error { // github // https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ -func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { - - // TODO: move to cfg package - userInfoURL := "https://api.github.com/user?access_token=" - if genOauth.UserInfoURL != "" { - userInfoURL = genOauth.UserInfoURL - } +func getUserInfoFromGitHub(client *http.Client, user *structs.User, ptoken *oauth2.Token) error { log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) - userinfo, err := client.Get(userInfoURL + ptoken.AccessToken) + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL + ptoken.AccessToken) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) return err @@ -525,14 +479,14 @@ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oaut defer userinfo.Body.Close() data, _ := ioutil.ReadAll(userinfo.Body) log.Println("github userinfo body: ", string(data)) - ghUser := structs.GithubUser{} + ghUser := structs.GitHubUser{} if err = json.Unmarshal(data, &ghUser); err != nil { log.Errorln(err) return err } - log.Debug("getUserInfoFromGithub ghUser") + log.Debug("getUserInfoFromGitHub ghUser") log.Debug(ghUser) - log.Debug("getUserInfoFromGithub user") + log.Debug("getUserInfoFromGitHub user") log.Debug(user) ghUser.PrepareUserData() @@ -542,7 +496,7 @@ func getUserInfoFromGithub(client *http.Client, user *structs.User, ptoken *oaut user.ID = ghUser.ID // user = &ghUser.User - log.Debug("getUserInfoFromGithub") + log.Debug("getUserInfoFromGitHub") log.Debug(user) return nil } @@ -561,19 +515,19 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { if _, err = fw.Write([]byte(code)); err != nil { return err } - // v.Set("redirect_uri", genOauth.RedirectURL) + // v.Set("redirect_uri", cfg.GenOAuth.RedirectURL) fw, err = w.CreateFormField("redirect_uri") - if _, err = fw.Write([]byte(genOauth.RedirectURL)); err != nil { + if _, err = fw.Write([]byte(cfg.GenOAuth.RedirectURL)); err != nil { return err } - // v.Set("client_id", genOauth.ClientID) + // v.Set("client_id", cfg.GenOAuth.ClientID) fw, err = w.CreateFormField("client_id") - if _, err = fw.Write([]byte(genOauth.ClientID)); err != nil { + if _, err = fw.Write([]byte(cfg.GenOAuth.ClientID)); err != nil { return err } w.Close() - req, err := http.NewRequest("POST", genOauth.AuthURL, &b) + req, err := http.NewRequest("POST", cfg.GenOAuth.AuthURL, &b) if err != nil { return err } @@ -581,7 +535,7 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { req.Header.Set("Accept", "application/json") // v := url.Values{} - // userinfo, err := client.PostForm(genOauth.UserInfoURL, v) + // userinfo, err := client.PostForm(cfg.GenOAuth.UserInfoURL, v) client := &http.Client{} userinfo, err := client.Do(req) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index bcfa5a99..8b9f4a5c 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -3,9 +3,15 @@ package cfg import ( "errors" "flag" + "io/ioutil" + "math/rand" "os" + "time" log "github.com/Sirupsen/logrus" + "golang.org/x/oauth2" + "golang.org/x/oauth2/github" + "golang.org/x/oauth2/google" "github.com/spf13/viper" ) @@ -32,8 +38,10 @@ type CfgT struct { } Headers struct { JWT string `mapstructure:"jwt"` + User string `mapstructure:"user"` QueryString string `mapstructure:"querystring"` Redirect string `mapstructure:"redirect"` + Success string `mapstructure:"success"` } DB struct { File string `mapstructure:"file"` @@ -43,28 +51,77 @@ type CfgT struct { } TestURL string `mapstructure:"test_url"` Testing bool `mapstructure:"testing"` + WebApp bool `mapstructure:"webapp"` } -// Cfg the main exported config variable -var Cfg CfgT +// oauth config items endoint for access +type oauthConfig struct { + Provider string `mapstructure:"provider"` + ClientID string `mapstructure:"client_id"` + ClientSecret string `mapstructure:"client_secret"` + AuthURL string `mapstructure:"auth_url"` + TokenURL string `mapstructure:"token_url"` + RedirectURL string `mapstructure:"callback_url"` + RedirectURLs []string `mapstructure:"callback_urls"` + Scopes []string `mapstructure:"scopes"` + UserInfoURL string `mapstructure:"user_info_url"` + PreferredDomain string `mapstructre:"preferredDomain"` +} + +// OAuthProviders holds the stings for +type OAuthProviders struct { + Google string + GitHub string + IndieAuth string + OIDC string +} + +var ( + // Cfg the main exported config variable + Cfg CfgT + + // GenOAuth exported OAuth config variable + // TODO: I think GenOAuth and OAuthConfig can be combined! + // perhaps by https://golang.org/doc/effective_go.html#embedding + GenOAuth *oauthConfig + + // OAuthClient is the configured client which will call the provider + // this actually carries the oauth2 client ala oauthclient.Client(oauth2.NoContext, providerToken) + OAuthClient *oauth2.Config + // OAuthopts authentication options + OAuthopts oauth2.AuthCodeOption + + // Providers static strings to test against + Providers = &OAuthProviders{ + Google: "google", + GitHub: "github", + IndieAuth: "indieauth", + OIDC: "oidc", + } +) // RequiredOptions must have these fields set for minimum viable config -var RequiredOptions = []string{"lasso.port", "lasso.listen", "lasso.jwt.secret", "lasso.db.file", "oauth.provider", "oauth.client_id"} +var RequiredOptions = []string{"oauth.provider", "oauth.client_id"} func init() { + // from config file ParseConfig() + + // can pass loglevel on the command line var ll = flag.String("loglevel", Cfg.LogLevel, "enable debug log output") flag.Parse() if *ll == "debug" { log.SetLevel(log.DebugLevel) log.Debug("logLevel set to debug") } + + setDefaults() log.Debug(viper.AllSettings()) } // ParseConfig parse the config file func ParseConfig() { - log.Info("opening config") + log.Debug("opening config") viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath(os.Getenv("LASSO_ROOT") + "config") @@ -79,13 +136,6 @@ func ParseConfig() { // log.Fatalf(err.prob) panic(errT) } - // nested defaults is currently *broken* - // https://github.com/spf13/viper/issues/309 - // viper.SetDefault("listen", "0.0.0.0") - // viper.SetDefault(Cfg.Port, 9090) - // viper.SetDefault("Headers.SSO", "X-Lasso-Token") - // viper.SetDefault("Headers.Redirect", "X-Lasso-Requested-URI") - // viper.SetDefault("Cookie.Name", "Lasso") log.Debugf("secret: %s", string(Cfg.JWT.Secret)) } @@ -108,3 +158,189 @@ func BasicTest() error { } return nil } + +// setDefaults set default options for some items +func setDefaults() { + + // this should really be done by Viper up in parseConfig but.. + // nested defaults is currently *broken* + // https://github.com/spf13/viper/issues/309 + // viper.SetDefault("listen", "0.0.0.0") + // viper.SetDefault(Cfg.Port, 9090) + // viper.SetDefault("Headers.SSO", "X-Lasso-Token") + // viper.SetDefault("Headers.Redirect", "X-Lasso-Requested-URI") + // viper.SetDefault("Cookie.Name", "Lasso") + + // logging + if !viper.IsSet("lasso.logLevel") { + Cfg.LogLevel = "info" + } + // network defaults + if !viper.IsSet("lasso.listen") { + Cfg.Listen = "0.0.0.0" + } + if !viper.IsSet("lasso.port") { + Cfg.Port = 9090 + } + if !viper.IsSet("lasso.allowAllUsers") { + Cfg.AllowAllUsers = false + } + if !viper.IsSet("lasso.publicAccess") { + Cfg.PublicAccess = false + } + + // jwt defaults + if !viper.IsSet("lasso.jwt.secret") { + Cfg.JWT.Secret = getOrGenerateJWTSecret() + } + if !viper.IsSet("lasso.jwt.issuer") { + Cfg.JWT.Issuer = "Lasso" + } + if !viper.IsSet("lasso.jwt.maxAge") { + Cfg.JWT.MaxAge = 240 + } + if !viper.IsSet("lasso.jwt.compress") { + Cfg.JWT.Compress = true + } + + // cookie defaults + if !viper.IsSet("lasso.cookie.name") { + Cfg.Cookie.Name = "LassoCookie" + } + if !viper.IsSet("lasso.cookie.secure") { + Cfg.Cookie.Secure = false + } + if !viper.IsSet("lasso.cookie.httpOnly") { + Cfg.Cookie.HTTPOnly = true + } + + // headers defaults + if !viper.IsSet("lasso.headers.jwt") { + Cfg.Headers.JWT = "X-Lasso-Token" + } + if !viper.IsSet("lasso.headers.querystring") { + Cfg.Headers.QueryString = "access_token" + } + if !viper.IsSet("lasso.headers.redirect") { + Cfg.Headers.Redirect = "X-Lasso-Requested-URI" + } + if !viper.IsSet("lasso.headers.user") { + Cfg.Headers.User = "X-Lasso-User" + } + if !viper.IsSet("lasso.headers.success") { + Cfg.Headers.Success = "X-Lasso-Success" + } + + // db defaults + if !viper.IsSet("lasso.db.file") { + Cfg.DB.File = "data/lasso_bolt.db" + } + + // session HERE + if !viper.IsSet("lasso.session.name") { + Cfg.Session.Name = "lassoSession" + } + + // testing convenience variable + if !viper.IsSet("lasso.testing") { + Cfg.Testing = false + } + if !viper.IsSet("lasso.test_url") { + Cfg.TestURL = "" + } + // TODO: proably change this name, maybe set the domain/port the webapp runs on + if !viper.IsSet("lasso.webapp") { + Cfg.WebApp = false + } + + // OAuth defaults and client configuration + err := UnmarshalKey("oauth", &GenOAuth) + if err == nil { + if GenOAuth.Provider == Providers.Google { + setDefaultsGoogle() + // setDefaultsGoogle also configures the OAuthClient + } else if GenOAuth.Provider == Providers.GitHub { + setDefaultsGitHub() + configureOAuthClient() + } else { + configureOAuthClient() + } + } +} + +func setDefaultsGoogle() { + log.Info("configuring Google OAuth") + GenOAuth.UserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo" + OAuthClient = &oauth2.Config{ + ClientID: GenOAuth.ClientID, + ClientSecret: GenOAuth.ClientSecret, + Scopes: []string{ + // You have to select a scope from + // https://developers.google.com/identity/protocols/googlescopes#google_sign-in + "https://www.googleapis.com/auth/userinfo.email", + }, + Endpoint: google.Endpoint, + } + log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) + OAuthopts = oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain) +} + +func setDefaultsGitHub() { + // log.Info("configuring GitHub OAuth") + if GenOAuth.AuthURL == "" { + GenOAuth.AuthURL = github.Endpoint.AuthURL + } + if GenOAuth.TokenURL == "" { + GenOAuth.TokenURL = github.Endpoint.TokenURL + } + if GenOAuth.UserInfoURL == "" { + GenOAuth.UserInfoURL = "https://api.github.com/user?access_token=" + } + if len(GenOAuth.Scopes) == 0 { + GenOAuth.Scopes = []string{"user"} + } +} + +func configureOAuthClient() { + log.Infof("configuring %s OAuth with Endpoint %s", GenOAuth.Provider, GenOAuth.AuthURL) + OAuthClient = &oauth2.Config{ + ClientID: GenOAuth.ClientID, + ClientSecret: GenOAuth.ClientSecret, + Endpoint: oauth2.Endpoint{ + AuthURL: GenOAuth.AuthURL, + TokenURL: GenOAuth.TokenURL, + }, + RedirectURL: GenOAuth.RedirectURL, + Scopes: GenOAuth.Scopes, + } +} + +var secretFile = os.Getenv("LASSO_ROOT") + "config/secret" + +// a-z A-Z 0-9 except no l, o, O +const charRunes = "abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ012346789" + +const secretLen = 18 + +func getOrGenerateJWTSecret() string { + b, err := ioutil.ReadFile(secretFile) + if err == nil { + log.Info("jwt.secret read from " + secretFile) + } else { + // then generate a new secret and store it in the file + log.Debug(err) + log.Info("jwt.secret not found in " + secretFile) + log.Warn("generating new jwt.secret and storing it in " + secretFile) + + rand.Seed(time.Now().UnixNano()) + b := make([]byte, secretLen) + for i := range b { + b[i] = charRunes[rand.Intn(len(charRunes))] + } + err := ioutil.WriteFile(secretFile, b, 0600) + if err != nil { + log.Debug(err) + } + } + return string(b) +} diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 04126902..2557706e 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -38,6 +38,9 @@ func init() { } Sites = make([]string, 0) + // TODO: the Sites that end up in the JWT come from here + // if we add fine grain ability (ACL?) to the equation + // then we're going to have to add something fancier here for i := 0; i < len(cfg.Cfg.Domains); i++ { Sites = append(Sites, cfg.Cfg.Domains[i]) } @@ -129,7 +132,7 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { func SiteInClaims(site string, claims *LassoClaims) bool { for _, s := range claims.Sites { if strings.Contains(site, s) { - log.Debugf("evaluating %s contains %s", site, s) + log.Debugf("site %s is found for claims.Site %s", site, s) return true } } diff --git a/pkg/model/model.go b/pkg/model/model.go index 6dd8e2b4..d5c3eef3 100644 --- a/pkg/model/model.go +++ b/pkg/model/model.go @@ -25,6 +25,8 @@ var ( //Db holds the db Db *bolt.DB + dbpath string + userBucket = []byte("users") teamBucket = []byte("teams") siteBucket = []byte("sites") @@ -32,11 +34,12 @@ var ( // may want to use encode/gob to store the user record func init() { - Db, _ = Open(os.Getenv("LASSO_ROOT") + cfg.Cfg.DB.File) + dbpath = os.Getenv("LASSO_ROOT") + cfg.Cfg.DB.File + Db, _ = OpenDB(dbpath) } -// Open the boltdb -func Open(dbfile string) (*bolt.DB, error) { +// OpenDB the boltdb +func OpenDB(dbfile string) (*bolt.DB, error) { opts := &bolt.Options{ Timeout: 50 * time.Millisecond, @@ -54,7 +57,9 @@ func Open(dbfile string) (*bolt.DB, error) { func getBucket(tx *bolt.Tx, key []byte) *bolt.Bucket { b, err := tx.CreateBucketIfNotExists(key) if err != nil { - log.Errorf("could not create bucket %s", err) + log.Errorf("could not create bucket in db %s", err) + log.Errorf("check the dbfile permissions at %s", dbpath) + log.Errorf("if there's really something wrong with the data ./do.sh includes a utility to browse the dbfile") return nil } return b diff --git a/pkg/model/model_test.go b/pkg/model/model_test.go index dab3fe1b..f2f83d00 100644 --- a/pkg/model/model_test.go +++ b/pkg/model/model_test.go @@ -17,14 +17,14 @@ import ( var testdb = "/tmp/storage-test.db" func init() { - Db, _ = Open(testdb) + Db, _ = OpenDB(testdb) log.SetLevel(log.DebugLevel) } func TestPutUserGetUser(t *testing.T) { os.Remove(testdb) - Open(testdb) + OpenDB(testdb) u1 := structs.User{ Email: "test@testing.com", @@ -58,7 +58,7 @@ func TestPutUserGetUser(t *testing.T) { func TestPutSiteGetSite(t *testing.T) { os.Remove(testdb) - Open(testdb) + OpenDB(testdb) s1 := structs.Site{Domain: "test.bnf.net"} s2 := &structs.Site{} @@ -73,7 +73,7 @@ func TestPutSiteGetSite(t *testing.T) { func TestPutTeamGetTeamDeleteTeam(t *testing.T) { os.Remove(testdb) - Open(testdb) + OpenDB(testdb) t1 := structs.Team{Name: "testname"} t2 := &structs.Team{} diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 0e59f97d..62ab2481 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -7,9 +7,12 @@ type UserI interface { // User is inherited. type User struct { + // TODO: set Provider here so that we can pass it to db + // populated by db (via mapstructure) or from provider (via json) + // Provider string `json:"provider",mapstructure:"provider"` Username string `json:"username",mapstructure:"username"` - Name string `json:"name"` - Email string `json:"email"` + Name string `json:"name",mapstructure:"name"` + Email string `json:"email",mapstructure:"email"` CreatedOn int64 `json:"createdon"` LastUpdate int64 `json:"lastupdate"` ID int `json:"id",mapstructure:"id"` @@ -23,6 +26,9 @@ func (u *User) PrepareUserData() { // GoogleUser is a retrieved and authentiacted user from Google. // unused! + +// TODO: see if these should be pointers to the *User object as per +// https://golang.org/doc/effective_go.html#embedding type GoogleUser struct { User Sub string `json:"sub"` @@ -41,8 +47,8 @@ func (u *GoogleUser) PrepareUserData() { u.Username = u.Email } -// GithubUser is a retrieved and authentiacted user from Github. -type GithubUser struct { +// GitHubUser is a retrieved and authentiacted user from GitHub. +type GitHubUser struct { User Login string `json:"login"` Picture string `json:"avatar_url"` @@ -50,34 +56,20 @@ type GithubUser struct { } // PrepareUserData implement PersonalData interface -func (u *GithubUser) PrepareUserData() { +func (u *GitHubUser) PrepareUserData() { // always use the u.Login as the u.Username u.Username = u.Login } type IndieAuthUser struct { User - URL string `json:"me"` + URL string `json:"me"` } func (u *IndieAuthUser) PrepareUserData() { u.Username = u.URL } -// GenericOauth provides endoint for access -type GenericOauth struct { - ClientID string `mapstructure:"client_id"` - ClientSecret string `mapstructure:"client_secret"` - AuthURL string `mapstructure:"auth_url"` - TokenURL string `mapstructure:"token_url"` - RedirectURL string `mapstructure:"callback_url"` - RedirectURLs []string `mapstructure:"callback_urls"` - Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url"` - Provider string `mapstructure:"provider"` - PreferredDomain string `mapstructre:"preferredDomain"` -} - // Team has members and provides acess to sites type Team struct { Name string `json:"name",mapstructure:"name"` From f3f7d00c302073ec4ced818f5323abd7267db352 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:33:27 -0700 Subject: [PATCH 047/736] #23 email --> username --- pkg/jwtmanager/jwtmanager_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index b9211cd7..619a2152 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -5,6 +5,7 @@ import ( "github.com/LassoProject/lasso/pkg/cfg" "github.com/LassoProject/lasso/pkg/structs" + // log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -12,7 +13,7 @@ import ( var ( u1 = structs.User{ - Email: "test@testing.com", + Username: "test@testing.com", EmailVerified: true, Name: "Test Name", } @@ -24,13 +25,13 @@ func init() { // log.SetLevel(log.DebugLevel) lc = LassoClaims{ - u1.Email, + u1.Username, Sites, StandardClaims, } } -func TestCreateUserTokenStringAndParseToEmail(t *testing.T) { +func TestCreateUserTokenStringAndParseToUsername(t *testing.T) { uts := CreateUserTokenString(u1) assert.NotEmpty(t, uts) @@ -40,8 +41,8 @@ func TestCreateUserTokenStringAndParseToEmail(t *testing.T) { t.Error(err) } else { log.Debugf("test parsed token string %v", utsParsed) - ptemail, _ := PTokenToEmail(utsParsed) - assert.Equal(t, u1.Email, ptemail) + ptUsername, _ := PTokenToUsername(utsParsed) + assert.Equal(t, u1.Username, ptUsername) } } From ae9218a603cf20bfab65a136ea13dbdca9dd96ee Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:34:02 -0700 Subject: [PATCH 048/736] fix #17 provid example configs and better explanation for config items --- config/config.yml_example | 51 +++++++++++++-------- config/config.yml_example_github | 31 +++++++++++++ config/config.yml_example_github_enterprise | 31 +++++++++++++ config/config.yml_example_google | 20 ++++++++ config/config.yml_example_indieauth | 24 ++++++++++ config/config.yml_example_oidc | 31 +++++++++++++ 6 files changed, 170 insertions(+), 18 deletions(-) create mode 100644 config/config.yml_example_github create mode 100644 config/config.yml_example_github_enterprise create mode 100644 config/config.yml_example_google create mode 100644 config/config.yml_example_indieauth create mode 100644 config/config.yml_example_oidc diff --git a/config/config.yml_example b/config/config.yml_example index 06dddcb9..7c22a388 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -5,14 +5,6 @@ lasso: listen: 0.0.0.0 port: 9090 - # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider - allowAllUsers: false - - # Setting publicAccess: true will accept all requests, even without a cookie. - # If the user is logged in, the cookie will be validated and the user header will be set. - # You will need to direct people to the Lasso login page from your application. - publicAccess: false - # each of these domains must serve the url https://lasso.$domains[0] https://lasso.$domains[1] ... # so that the cookie which stores the JWT can be set in the relevant domain # usually you'll just have one. @@ -21,22 +13,39 @@ lasso: - yourdomain.com - yourotherdomain.com + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider + allowAllUsers: false + + # Setting publicAccess: true will accept all requests, even without a cookie. + # If the user is logged in, the cookie will be validated and the user header will be set. + # You will need to direct people to the Lasso login page from your application. + publicAccess: false + jwt: + # secret: a random 18 character string used to cryptographically sign the jwt + # if the secret is not set here then.. + # look for the secret in `./config/secret` + # if `./config/secret` doesn't exist then randomly generate a secret and store it there + # in order to run multiple instances of lasso on multiple servers (perhaps purely for validating the jwt), + # you'll want them all to have the same secret + secret: your_random_string issuer: Lasso + # number of seconds until jwt expires maxAge: 240 - secret: your_random_string + # compress the jwt compress: true cookie: # name of cookie to store the jwt - name: Lasso-cookie + name: LassoCookie # optionally force the domain of the cookie to set # domain: yourdomain.com secure: true httpOnly: true session: - name: lasso-session + # just the name of session variable stored locally + name: lassoSession headers: jwt: X-Lasso-Token @@ -46,13 +55,18 @@ lasso: db: file: data/lasso_bolt.db + # testing: force all 302 redirects to be rendered as a webpage with a link + testing: true + # test_url: add this URL to the page which lasso displays test_url: http://yourdomain.com + # webapp: WIP for web interface to lasso (mostly logs) + webapp: true # -# OAuth Provider Config +# OAuth Provider +# configure ONLY ONE of the following oauth providers # oauth: - # configure only one of the following # Google provider: google @@ -70,13 +84,14 @@ oauth: provider: github client_id: client_secret: - auth_url: https://github.com/login/oauth/authorize - token_url: https://github.com/login/oauth/access_token # callback_url is configured at github.com when setting up the app # set to e.g. https://lasso.yourdomain.com/auth - scopes: - - user - user_info_url: https://api.github.com/user?access_token= + # defaults (uncomment and change these if you are using github enterprise on-prem) + # auth_url: https://github.com/login/oauth/authorize + # token_url: https://github.com/login/oauth/access_token + # user_info_url: https://api.github.com/user?access_token= + # scopes: + # - user # Generic OpenID Connect provider: oidc diff --git a/config/config.yml_example_github b/config/config.yml_example_github new file mode 100644 index 00000000..9924450f --- /dev/null +++ b/config/config.yml_example_github @@ -0,0 +1,31 @@ + +# lasso config +# bare minimum to get lasso running with github + +lasso: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + # for github that's only one domain since they only allow one callback URL + # https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#redirect-urls + # each of these domains must serve the url https://login.$domains[0] https://login.$domains[1] ... + domains: + - yourothersite.io + + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at GitHub + # allowAllUsers: true + +oauth: + # create a new OAuth application at: + # https://github.com/settings/applications/new + provider: github + client_id: xxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + # these GitHub OAuth defaults are set for you.. + # from https://godoc.org/golang.org/x/oauth2/github + # auth_url: https://github.com/login/oauth/authorize + # token_url: https://github.com/login/oauth/access_token + # scopes: + # - user + # user_info_url: https://api.github.com/user?access_token= \ No newline at end of file diff --git a/config/config.yml_example_github_enterprise b/config/config.yml_example_github_enterprise new file mode 100644 index 00000000..3d1eec6e --- /dev/null +++ b/config/config.yml_example_github_enterprise @@ -0,0 +1,31 @@ +# lasso config +# bare minimum to get lasso running with github enterprise +# see config.yml_example for all options + +lasso: + # domains: + # valid domains that the jwt cookies can be set into + # each of these domains must serve the url https://login.$domains[0] https://login.$domains[1] ... + # the callback_urls will be to these domains + domains: + - yoursite.com + - yourothersite.io + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider + # allowAllUsers: true + +oauth: + # create a new OAuth application at: + # https://githubenterprise.yoursite.com/settings/applications/new + provider: github + client_id: xxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + auth_url: https://githubenterprise.yoursite.com/login/oauth/authorize + token_url: https://githubenterprise.yoursite.com/login/oauth/access_token + user_info_url: https://githubenterprise.yoursite.com/user?access_token= + + # these GitHub OAuth defaults are set for you.. + # scopes: + # - user diff --git a/config/config.yml_example_google b/config/config.yml_example_google new file mode 100644 index 00000000..57770053 --- /dev/null +++ b/config/config.yml_example_google @@ -0,0 +1,20 @@ + +# lasso config +# bare minimum to get lasso running with google + +lasso: + domains: + - yourdomain.com + - yourotherdomain.com + +oauth: + provider: google + # get credentials from... + # https://console.developers.google.com/apis/credentials + client_id: xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + callback_urls: + - http://yourdomain.com:9090/auth + - http://yourotherdomain.com:9090/auth + preferredDomain: yourdomain.com + # endpoints set from https://godoc.org/golang.org/x/oauth2/google diff --git a/config/config.yml_example_indieauth b/config/config.yml_example_indieauth new file mode 100644 index 00000000..6c4fb678 --- /dev/null +++ b/config/config.yml_example_indieauth @@ -0,0 +1,24 @@ + +# lasso config +# bare minimum to get lasso running with IndieAuth + +lasso: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + - yourdomain.com + + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider + allowAllUsers: true + + # Setting publicAccess: true will accept all requests, even without a cookie. + publicAccess: true + +oauth: + # IndieAuth + # https://indielogin.com/api + provider: indieauth + client_id: http://yourdomain.com + auth_url: https://indielogin.com/auth + callback_url: http://lasso.yourdomain.com:9090/auth diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc new file mode 100644 index 00000000..41be4c96 --- /dev/null +++ b/config/config.yml_example_oidc @@ -0,0 +1,31 @@ + +# lasso config +# bare minimum to get lasso running with OpenID Connect (such as okta) + +lasso: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + - yourdomain.com + - yourotherdomain.com + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Lasso to just accept anyone who can authenticate at the configured provider + # allowAllUsers: true + +oauth: + # Generic OpenID Connect + # including okta + provider: oidc + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize + token_url: https://{yourOktaDomain}/oauth2/default/v1/token + user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo + scopes: + - openid + - email + - profile + callback_url: http://lasso.yourdomain.com:9090/auth From 7512dc75c8d366709fed6cd9133f9e66b4b3bee1 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Oct 2018 16:34:57 -0700 Subject: [PATCH 049/736] ignore local configs --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 02aec4ee..78910f1f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ main config/google_config.json .vscode/* lasso +config/config.yml_google +config/config.yml_github +config/secret +config/config.yml_orig From 6ac752588c3b6a898f704f072d8509761f4e4701 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 12 Oct 2018 16:09:44 -0700 Subject: [PATCH 050/736] add whitelist capabilities --- Dockerfile | 2 +- config/config.yml_example | 4 ++++ handlers/handlers.go | 8 ++++++++ pkg/cfg/cfg.go | 7 ++++--- pkg/cfg/cfg_test.go | 2 +- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8664a808..9a74f289 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# bfoote/lasso +# lassoproject/lasso # https://github.com/LassoProject/lasso FROM golang:1.8 diff --git a/config/config.yml_example b/config/config.yml_example index 7c22a388..3e265b9c 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -21,6 +21,10 @@ lasso: # You will need to direct people to the Lasso login page from your application. publicAccess: false + TODO: + whiteList: + - + jwt: # secret: a random 18 character string used to cryptographically sign the jwt # if the secret is not set here then.. diff --git a/handlers/handlers.go b/handlers/handlers.go index 8b2aa8ad..d13c2cdf 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -331,6 +331,14 @@ func VerifyUser(u interface{}) (ok bool, err error) { ok = true log.Debugf("skipping verify user since cfg.Cfg.AllowAllUsers is %t", cfg.Cfg.AllowAllUsers) // if we're not allowing all users, and we have domains configured and this email isn't in one of those domains... + } else if len(cfg.Cfg.WhiteList) != 0 { + for _, wl := range cfg.Cfg.WhiteList { + if user.Username == wl { + log.Debugf("found user.Username in WhiteList: %s", user.Username) + ok = true + break + } + } } else if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { err = fmt.Errorf("Email %s is not within a lasso managed domain", user.Email) // } else if !domains.IsUnderManagement(user.HostDomain) { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 8b9f4a5c..0d93cd2e 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -16,12 +16,13 @@ import ( "github.com/spf13/viper" ) -// CfgT lasso jwt cookie configuration -type CfgT struct { +// config lasso jwt cookie configuration +type config struct { LogLevel string `mapstructure:"logLevel"` Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` Domains []string `mapstructure:"domains"` + WhiteList []string `mapstructure:"whitelist"` AllowAllUsers bool `mapstructure:"allowAllUsers"` PublicAccess bool `mapstructure:"publicAccess"` JWT struct { @@ -78,7 +79,7 @@ type OAuthProviders struct { var ( // Cfg the main exported config variable - Cfg CfgT + Cfg config // GenOAuth exported OAuth config variable // TODO: I think GenOAuth and OAuthConfig can be combined! diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index c8a21064..a19726b2 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -9,7 +9,7 @@ import ( ) var ( - cfg CfgT + cfg config ) func init() { From ae15a64bcbb443ec4dac96747ef5e5a83877df35 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 17 Oct 2018 14:36:08 -0700 Subject: [PATCH 051/736] record StatusCode for better loggin --- handlers/handlers.go | 57 +++++++++++++++++++++++----------------- pkg/context/context.go | 10 ------- pkg/response/response.go | 41 +++++++++++++++++++++++++++++ pkg/timelog/timelog.go | 29 +++++++++----------- 4 files changed, 86 insertions(+), 51 deletions(-) delete mode 100644 pkg/context/context.go create mode 100644 pkg/response/response.go diff --git a/handlers/handlers.go b/handlers/handlers.go index d13c2cdf..d6a18f43 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -2,7 +2,6 @@ package handlers import ( "bytes" - "context" "crypto/rand" "encoding/base64" "encoding/json" @@ -16,7 +15,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/LassoProject/lasso/pkg/cfg" - lctx "github.com/LassoProject/lasso/pkg/context" "github.com/LassoProject/lasso/pkg/cookie" "github.com/LassoProject/lasso/pkg/domains" "github.com/LassoProject/lasso/pkg/jwtmanager" @@ -135,33 +133,19 @@ func ClaimsFromJWT(jwt string) (jwtmanager.LassoClaims, error) { return claims, nil } -// the standard error -// this is captured by nginx, which converts the 401 into 302 to the login page -func error401(w http.ResponseWriter, r *http.Request, ae AuthError) { - log.Error(ae.Error) - cookie.ClearCookie(w, r) - context.WithValue(r.Context(), lctx.StatusCode, http.StatusUnauthorized) - // w.Header().Set("X-Lasso-Error", ae.Error) - http.Error(w, ae.Error, http.StatusUnauthorized) - // TODO put this back in place if multiple auth mechanism are available - // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": errStr}) -} - -func error401na(w http.ResponseWriter, r *http.Request) { - error401(w, r, AuthError{Error: "not authorized"}) -} - // ValidateRequestHandler /validate // TODO this should use the handler interface func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { log.Debug("/validate") + // TODO: collapse all of the `if !cfg.Cfg.PublicAccess` calls + // perhaps using an `ok=false` pattern jwt := FindJWT(r) // if jwt != "" { if jwt == "" { // If the module is configured to allow public access with no authentication, return 200 now if !cfg.Cfg.PublicAccess { - error401(w, r, AuthError{Error: "no jwt found in request for "}) + error401(w, r, AuthError{Error: "no jwt found in request"}) } else { w.Header().Add(cfg.Cfg.Headers.User, "") } @@ -178,6 +162,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } return } + if claims.Username == "" { // no email in jwt if !cfg.Cfg.PublicAccess { @@ -204,7 +189,9 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { w.Header().Add(cfg.Cfg.Headers.User, claims.Username) w.Header().Add(cfg.Cfg.Headers.Success, "true") log.Debugf("response header "+cfg.Cfg.Headers.User+": %s", w.Header().Get(cfg.Cfg.Headers.User)) - renderIndex(w, "/validate user found in jwt "+claims.Username) + + // good to go!! + ok200(w, r) // TODO // parse the jwt and see if the claim is valid for the domain @@ -305,7 +292,6 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // bounce to oauth provider for login var lURL = loginURL(r, state) log.Debugf("redirecting to oauthURL %s", lURL) - context.WithValue(r.Context(), lctx.StatusCode, 302) redirect302(w, r, lURL) } } @@ -405,8 +391,6 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { session.Values[requestedURL] = 0 session.Save(r, w) - // and redirect - context.WithValue(r.Context(), lctx.StatusCode, 302) redirect302(w, r, requestedURL) return } @@ -566,13 +550,38 @@ func getUserInfoFromIndieAuth(r *http.Request, user *structs.User) error { return nil } +// the standard error +// this is captured by nginx, which converts the 401 into 302 to the login page +func error401(w http.ResponseWriter, r *http.Request, ae AuthError) { + log.Error(ae.Error) + cookie.ClearCookie(w, r) + // w.Header().Set("X-Lasso-Error", ae.Error) + http.Error(w, ae.Error, http.StatusUnauthorized) + // TODO put this back in place if multiple auth mechanism are available + // c.HTML(http.StatusBadRequest, "error.tmpl", gin.H{"message": errStr}) +} + +func error401na(w http.ResponseWriter, r *http.Request) { + error401(w, r, AuthError{Error: "not authorized"}) +} + func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { if cfg.Cfg.Testing { var tmp = cfg.Cfg.TestURL cfg.Cfg.TestURL = rURL + // TODO: allow template to take an array of URLs and just push to those renderIndex(w, "302 redirect to: "+cfg.Cfg.TestURL) cfg.Cfg.TestURL = tmp return } - http.Redirect(w, r, rURL, 302) + http.Redirect(w, r, rURL, http.StatusFound) +} + +func ok200(w http.ResponseWriter, r *http.Request) { + + n, err := w.Write(nil) + if err != nil { + log.Error(err) + } + log.Debugf("ok200 with empty body (bytes %d)", n) } diff --git a/pkg/context/context.go b/pkg/context/context.go deleted file mode 100644 index 3cc719bb..00000000 --- a/pkg/context/context.go +++ /dev/null @@ -1,10 +0,0 @@ -package context - -// Key named keys for context map -type Key string - -func (c Key) String() string { - return "mypackage context key " + string(c) -} - -var StatusCode = Key("statusCode") diff --git a/pkg/response/response.go b/pkg/response/response.go new file mode 100644 index 00000000..ff7bfd8c --- /dev/null +++ b/pkg/response/response.go @@ -0,0 +1,41 @@ +package response + +import "net/http" +import log "github.com/Sirupsen/logrus" + +// we wrap ResponseWriter so that we can store the StatusCode +// and then pull it out later for logging +// https://play.golang.org/p/wPHaX9DH-Ik + +// CaptureWriter extends http.ResponseWriter +type CaptureWriter struct { + http.ResponseWriter + StatusCode int +} + +func (w *CaptureWriter) Write(b []byte) (int, error) { + if w.StatusCode == 0 { + w.StatusCode = 200 + log.Debugf("set w.StatusCode %d", w.StatusCode) + } + log.Debugf("CaptureWriter.Write code %d", w.StatusCode) + return w.ResponseWriter.Write(b) +} + +// Header calls http.Writer.Header() +func (w *CaptureWriter) Header() http.Header { + log.Debugf("CaptureWriter.Header code %d", w.StatusCode) + return w.ResponseWriter.Header() +} + +// WriteHeader calls http.Writer.WriteHeader(code) +func (w *CaptureWriter) WriteHeader(code int) { + w.StatusCode = code + log.Debugf("CaptureWriter.WriteHeader code %d", w.StatusCode) + w.ResponseWriter.WriteHeader(code) +} + +// GetStatusCode return w.StatusCode +func (w *CaptureWriter) GetStatusCode() int { + return w.StatusCode +} diff --git a/pkg/timelog/timelog.go b/pkg/timelog/timelog.go index 810e82ee..6cde0c29 100644 --- a/pkg/timelog/timelog.go +++ b/pkg/timelog/timelog.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - lctx "github.com/LassoProject/lasso/pkg/context" + "github.com/LassoProject/lasso/pkg/response" log "github.com/Sirupsen/logrus" // "github.com/mattn/go-isatty" @@ -22,38 +22,33 @@ var ( reset = string([]byte{27, 91, 48, 109}) ) -// HERE you left off trying to figure out how to implement middleware in gorilla mux -func TimeLog(nextHandler http.Handler) http.HandlerFunc { +// TimeLog records how long it takes to process the http request and produce the response (latency) +func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - log.Debugf("Request received : %v\n", r) + log.Debugf("Request received : %v", r) start := time.Now() // make the call + v := response.CaptureWriter{w, 0} ctx := context.Background() - nextHandler.ServeHTTP(w, r.WithContext(ctx)) + nextHandler.ServeHTTP(&v, r.WithContext(ctx)) // Stop timer end := time.Now() - log.Debug("Request handled successfully") latency := end.Sub(start) - clientIP := r.RemoteAddr - method := r.Method - // var statusCode int - // var statusColor string - statusCode := ctx.Value(lctx.StatusCode) - // TODO: this just doesn't seem to work, how can we get the statusCode from the context? - // log.Debugf("statuscode: %v", statusCode) - if statusCode == nil { - statusCode = 200 - } - statusColor := colorForStatus(statusCode.(int)) + log.Debugf("Request handled successfully: %v", v.GetStatusCode()) + var statusCode = v.GetStatusCode() + statusColor := colorForStatus(statusCode) path := r.URL.Path host := r.Host referer := r.Header.Get("Referer") + clientIP := r.RemoteAddr + method := r.Method + log.Infof("|%s %3d %s| %13v | %s | %s %s %s | %s", statusColor, statusCode, reset, latency, From 02762cd8295b326ecfaaed0dd6f8a819e31ffcc1 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 17 Oct 2018 15:43:25 -0700 Subject: [PATCH 052/736] record request number and average latency --- pkg/timelog/timelog.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/pkg/timelog/timelog.go b/pkg/timelog/timelog.go index 6cde0c29..5185166a 100644 --- a/pkg/timelog/timelog.go +++ b/pkg/timelog/timelog.go @@ -12,14 +12,16 @@ import ( ) var ( - green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) - white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) - yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) - red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) - blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) - magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) - cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) - reset = string([]byte{27, 91, 48, 109}) + green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) + white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) + yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) + red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) + blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) + magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) + cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) + reset = string([]byte{27, 91, 48, 109}) + req = int64(0) + avgLatency = int64(0) ) // TimeLog records how long it takes to process the http request and produce the response (latency) @@ -35,9 +37,9 @@ func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) // Stop timer end := time.Now() - latency := end.Sub(start) - + req++ + avgLatency = avgLatency + ((int64(latency) - avgLatency) / req) log.Debugf("Request handled successfully: %v", v.GetStatusCode()) var statusCode = v.GetStatusCode() statusColor := colorForStatus(statusCode) @@ -49,9 +51,9 @@ func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) clientIP := r.RemoteAddr method := r.Method - log.Infof("|%s %3d %s| %13v | %s | %s %s %s | %s", + log.Infof("|%s %3d %s| %d %10v %10v | %s | %s %s %s | %s", statusColor, statusCode, reset, - latency, + req, latency, time.Duration(avgLatency), clientIP, method, host, path, referer) From 839d952d5aa5d6d0e015c5314b9cf61eb148c1b3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 17 Oct 2018 16:26:03 -0700 Subject: [PATCH 053/736] append to TestURLs to capture full round trip of 302 redirects --- handlers/handlers.go | 13 +++++-------- pkg/cfg/cfg.go | 19 ++++++++++++------- templates/index.tmpl | 6 +++++- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index d6a18f43..adfcc1f6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -27,8 +27,8 @@ import ( // Index variables passed to index.tmpl // TODO: turn TestURL into an array of URLs to display type Index struct { - Msg string - TestURL string + Msg string + TestURLs []string } // AuthError sets the values to return to nginx @@ -297,7 +297,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { } func renderIndex(w http.ResponseWriter, msg string) { - if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURL: cfg.Cfg.TestURL}); err != nil { + if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURLs: cfg.Cfg.TestURLs}); err != nil { log.Error(err) } } @@ -567,11 +567,8 @@ func error401na(w http.ResponseWriter, r *http.Request) { func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { if cfg.Cfg.Testing { - var tmp = cfg.Cfg.TestURL - cfg.Cfg.TestURL = rURL - // TODO: allow template to take an array of URLs and just push to those - renderIndex(w, "302 redirect to: "+cfg.Cfg.TestURL) - cfg.Cfg.TestURL = tmp + cfg.Cfg.TestURLs = append(cfg.Cfg.TestURLs, rURL) + renderIndex(w, "302 redirect to: "+rURL) return } http.Redirect(w, r, rURL, http.StatusFound) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 0d93cd2e..6b4c955c 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -50,9 +50,10 @@ type config struct { Session struct { Name string `mapstructure:"name"` } - TestURL string `mapstructure:"test_url"` - Testing bool `mapstructure:"testing"` - WebApp bool `mapstructure:"webapp"` + TestURL string `mapstructure:"test_url"` + TestURLs []string `mapstructure:"test_urls"` + Testing bool `mapstructure:"testing"` + WebApp bool `mapstructure:"webapp"` } // oauth config items endoint for access @@ -246,8 +247,8 @@ func setDefaults() { if !viper.IsSet("lasso.testing") { Cfg.Testing = false } - if !viper.IsSet("lasso.test_url") { - Cfg.TestURL = "" + if viper.IsSet("lasso.test_url") { + Cfg.TestURLs = append(Cfg.TestURLs, Cfg.TestURL) } // TODO: proably change this name, maybe set the domain/port the webapp runs on if !viper.IsSet("lasso.webapp") { @@ -282,8 +283,12 @@ func setDefaultsGoogle() { }, Endpoint: google.Endpoint, } - log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) - OAuthopts = oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain) + if GenOAuth.PreferredDomain != "" { + log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) + OAuthopts = oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain) + } else { + OAuthopts = oauth2.SetAuthURLParam("hd", "") + } } func setDefaultsGitHub() { diff --git a/templates/index.tmpl b/templates/index.tmpl index ecfcf43b..31ba1acc 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -13,7 +13,11 @@

  • login
  • logout
  • validate
  • -
  • {{ .TestURL }}
  • +{{ if .TestURLs }} + {{ range $url := .TestURLs}} +
  • {{ $url }}
  • + {{ end }} +{{ end }} For support, please contact your network administrator or whomever setup nginx to use Lasso. From 6bc07e5eb10351bdd0ee36ff2475e36435fb3a6f Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Fri, 19 Oct 2018 10:31:57 -0700 Subject: [PATCH 054/736] use Provider from cfg Co-Authored-By: bnfinet --- handlers/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 8b2aa8ad..937b8cd8 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -411,7 +411,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { func getUserInfo(r *http.Request, user *structs.User) error { // indieauth sends the "me" setting in json back to the callback, so just pluck it from the callback - if cfg.GenOAuth.Provider == "indieauth" { + if cfg.GenOAuth.Provider == cfg.Providers.IndieAuth { return getUserInfoFromIndieAuth(r, user) } From 447db6de97f741b9c0492c77434f2119943a4e02 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 10:50:24 -0700 Subject: [PATCH 055/736] don't log in color if it's not a tty, structured logs, general cleanup --- handlers/handlers.go | 7 +++--- main.go | 8 +++--- pkg/cfg/cfg.go | 5 ++-- pkg/cookie/cookie.go | 8 ++++-- pkg/timelog/timelog.go | 45 ++++++++++++++++++++++++++++------ pkg/transciever/transciever.go | 4 +-- 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index adfcc1f6..2e0059c3 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -25,7 +25,6 @@ import ( ) // Index variables passed to index.tmpl -// TODO: turn TestURL into an array of URLs to display type Index struct { Msg string TestURLs []string @@ -172,7 +171,9 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } return } - log.Infof("username from jwt cookie: %s", claims.Username) + log.WithFields(log.Fields{ + "username": claims.Username, + }).Info("jwt cookie") if !cfg.Cfg.AllowAllUsers { if !jwtmanager.SiteInClaims(r.Host, &claims) { @@ -188,7 +189,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { // renderIndex(w, "user found from email "+user.Email) w.Header().Add(cfg.Cfg.Headers.User, claims.Username) w.Header().Add(cfg.Cfg.Headers.Success, "true") - log.Debugf("response header "+cfg.Cfg.Headers.User+": %s", w.Header().Get(cfg.Cfg.Headers.User)) + log.WithFields(log.Fields{cfg.Cfg.Headers.User: w.Header().Get(cfg.Cfg.Headers.User)}).Debug("response header") // good to go!! ok200(w, r) diff --git a/main.go b/main.go index 5330ab85..64ce5d3a 100644 --- a/main.go +++ b/main.go @@ -19,12 +19,9 @@ import ( func main() { log.Info("starting lasso") mux := http.NewServeMux() - // router := mux.NewRouter() - // router.HandleFunc("/", handlers.IndexHandler) authH := http.HandlerFunc(handlers.ValidateRequestHandler) mux.HandleFunc("/validate", timelog.TimeLog(authH)) - // mux.HandleFunc("/validate", handlers.ValidateRequestHandler) loginH := http.HandlerFunc(handlers.LoginHandler) mux.HandleFunc("/login", timelog.TimeLog(loginH)) @@ -35,7 +32,7 @@ func main() { callH := http.HandlerFunc(handlers.CallbackHandler) mux.HandleFunc("/auth", timelog.TimeLog(callH)) - // router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))) + // serve static files from /static mux.Handle("/static", http.FileServer(http.Dir("./static"))) if cfg.Cfg.WebApp { @@ -57,6 +54,9 @@ func main() { // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, + /// logrus has an example of using ErrorLog but it doesn't apply to this MUX implimentation + // https://github.com/sirupsen/logrus#logger-as-an-iowriter + // ErrorLog: log.New(w, "", 0), } log.Fatal(srv.ListenAndServe()) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 6b4c955c..e7cc544a 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -138,7 +138,8 @@ func ParseConfig() { // log.Fatalf(err.prob) panic(errT) } - log.Debugf("secret: %s", string(Cfg.JWT.Secret)) + // don't log the secret! + // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) } // UnmarshalKey populate struct from contents of cfg tree at key @@ -336,7 +337,7 @@ func getOrGenerateJWTSecret() string { // then generate a new secret and store it in the file log.Debug(err) log.Info("jwt.secret not found in " + secretFile) - log.Warn("generating new jwt.secret and storing it in " + secretFile) + log.Warn("generating random jwt.secret and storing it in " + secretFile) rand.Seed(time.Now().UnixNano()) b := make([]byte, secretLen) diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index a5ad22ee..885e575b 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -25,7 +25,7 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { domain := domains.Matches(r.Host) // Allow overriding the cookie domain in the config file if cfg.Cfg.Cookie.Domain != "" { - domain = cfg.Cfg.Cookie.Domain + domain = cfg.Cfg.Cookie.Domain log.Debugf("setting the cookie domain to %v", domain) } // log.Debugf("cookie %s expires %d", cfg.Cfg.Cookie.Name, expires) @@ -49,7 +49,11 @@ func Cookie(r *http.Request) (string, error) { if cookie.Value == "" { return "", errors.New("Cookie token empty") } - log.Debugf("cookie %s: %s", cfg.Cfg.Cookie.Name, cookie.Value) + + log.WithFields(log.Fields{ + "cookieName": cfg.Cfg.Cookie.Name, + "cookieValue": cookie.Value, + }).Debug("cookie") return cookie.Value, err } diff --git a/pkg/timelog/timelog.go b/pkg/timelog/timelog.go index 5185166a..f1a95952 100644 --- a/pkg/timelog/timelog.go +++ b/pkg/timelog/timelog.go @@ -2,16 +2,20 @@ package timelog import ( "context" + "fmt" "net/http" + "os" + "strconv" "time" "github.com/LassoProject/lasso/pkg/response" log "github.com/Sirupsen/logrus" - // "github.com/mattn/go-isatty" + isatty "github.com/mattn/go-isatty" ) var ( + useColor = false green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) @@ -24,6 +28,13 @@ var ( avgLatency = int64(0) ) +func init() { + if isatty.IsTerminal(os.Stdout.Fd()) { + useColor = true + } + // useColor = false +} + // TimeLog records how long it takes to process the http request and produce the response (latency) func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { @@ -42,7 +53,6 @@ func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) avgLatency = avgLatency + ((int64(latency) - avgLatency) / req) log.Debugf("Request handled successfully: %v", v.GetStatusCode()) var statusCode = v.GetStatusCode() - statusColor := colorForStatus(statusCode) path := r.URL.Path host := r.Host @@ -51,12 +61,24 @@ func TimeLog(nextHandler http.Handler) func(http.ResponseWriter, *http.Request) clientIP := r.RemoteAddr method := r.Method - log.Infof("|%s %3d %s| %d %10v %10v | %s | %s %s %s | %s", - statusColor, statusCode, reset, - req, latency, time.Duration(avgLatency), - clientIP, - method, host, path, - referer) + log.WithFields(log.Fields{ + "statusCode": statusCode, + "request": req, + "latency": fmt.Sprintf("%10v", time.Duration(latency)), + "avgLatency": fmt.Sprintf("%10v", time.Duration(avgLatency)), + "ipPort": clientIP, + "method": method, + "host": host, + "path": path, + "referer": referer, + }).Infof("|%s| %10v %s", colorStatus(statusCode), time.Duration(latency), path) + + // log.Infof("|%s %3d %s| %d %10v %10v | %s | %s %s %s | %s", + // statusColor, statusCode, reset, + // req, latency, time.Duration(avgLatency), + // clientIP, + // method, host, path, + // referer) } } @@ -72,3 +94,10 @@ func colorForStatus(code int) string { return red } } + +func colorStatus(code int) string { + if !useColor { + return strconv.Itoa(code) + } + return fmt.Sprintf("%s %3d %s", colorForStatus(code), code, reset) +} diff --git a/pkg/transciever/transciever.go b/pkg/transciever/transciever.go index 9925636d..2eb2e3d9 100644 --- a/pkg/transciever/transciever.go +++ b/pkg/transciever/transciever.go @@ -27,7 +27,7 @@ func ExplicitInit() { } func (WS WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - log.Infof("ws endpoint") + log.Info("ws endpoint") // jwt := handlers.FindJWT(r) // if jwt == "" { // http.Error(w, "your mother", http.StatusUnauthorized) @@ -42,6 +42,6 @@ func (WS WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // http.Error(w, "your mother", http.StatusUnauthorized) // return // } - log.Info("hub %v", hh.Hub) + log.Infof("hub %v", hh.Hub) serveWs(hh.Hub, w, r) } From 87ad3b3eca630e57cca500beae48cca4c3c8e6a4 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 10:54:58 -0700 Subject: [PATCH 056/736] even simpler! --- config/config.yml_example_github | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/config/config.yml_example_github b/config/config.yml_example_github index 9924450f..93b681eb 100644 --- a/config/config.yml_example_github +++ b/config/config.yml_example_github @@ -21,11 +21,4 @@ oauth: provider: github client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - - # these GitHub OAuth defaults are set for you.. - # from https://godoc.org/golang.org/x/oauth2/github - # auth_url: https://github.com/login/oauth/authorize - # token_url: https://github.com/login/oauth/access_token - # scopes: - # - user - # user_info_url: https://api.github.com/user?access_token= \ No newline at end of file + # endpoints set from https://godoc.org/golang.org/x/oauth2/github From c239e204c593236864b4ed2638a676f6bda7cd46 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 11:13:58 -0700 Subject: [PATCH 057/736] minor edit as per #22 --- config/config.yml_example_github_enterprise | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/config.yml_example_github_enterprise b/config/config.yml_example_github_enterprise index 3d1eec6e..79e73b8f 100644 --- a/config/config.yml_example_github_enterprise +++ b/config/config.yml_example_github_enterprise @@ -24,8 +24,7 @@ oauth: client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx auth_url: https://githubenterprise.yoursite.com/login/oauth/authorize token_url: https://githubenterprise.yoursite.com/login/oauth/access_token - user_info_url: https://githubenterprise.yoursite.com/user?access_token= - + user_info_url: https://githubenterprise.yoursite.com/api/v3/user?access_token= # these GitHub OAuth defaults are set for you.. # scopes: # - user From 7174b3f5ef2cafe3a749cbf56a00f8a6064bf368 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 13:10:23 -0700 Subject: [PATCH 058/736] general cleanup of README, do.sh, TODO --- README.md | 19 +++++---- TODO.md | 87 +++++++++++++++------------------------ do.sh | 34 ++++----------- lasso_flow.dot | 41 ------------------ lasso_flow.png | Bin 176681 -> 0 bytes pkg/response/response.go | 6 +-- 6 files changed, 54 insertions(+), 133 deletions(-) delete mode 100644 lasso_flow.dot delete mode 100644 lasso_flow.png diff --git a/README.md b/README.md index 0f8aefaa..03f76f80 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ an SSO solution for nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. -lasso supports OAuth login via Google, [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/), [IndieAuth](https://indieauth.spec.indieweb.org/), and OpenID Connect providers. +lasso supports OAuth login via Google, [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/), [IndieAuth](https://indieauth.spec.indieweb.org/), and OpenID Connect providers If lasso is running on the same host as the nginx reverse proxy the response time from the `/validate` endpoint to nginx should be less than 1ms @@ -11,7 +11,7 @@ For support please file tickets here or visit our IRC channel [#lasso](irc://fre ## Installation * `cp ./config/config.yml_example ./config/config.yml` -* create oauth credentials for lasso at [google](https://console.developers.google.com/apis/credentials) or [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) +* create OAuth credentials for lasso at [google](https://console.developers.google.com/apis/credentials) or [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) * be sure to direct the callback URL to the `/auth` endpoint * configure nginx... @@ -78,11 +78,16 @@ server { ## Running from Docker -* `./do.sh drun` - -And that's it! Or if you can examine the docker command in `do.sh` +```bash +docker run -d \ + -p 9090:9090 \ + --name lasso \ + -v ${PWD}/config:/config \ + -v ${PWD}/data:/data \ + lassoproject/lasso +``` -The [bfoote/lasso](https://hub.docker.com/r/bfoote/lasso/) Docker image is an automated build on Docker Hub +The [lassoproject/lasso](https://hub.docker.com/r/lassoproject/lasso/) Docker image is an automated build on Docker Hub ## Running from source @@ -134,4 +139,4 @@ Note that outside of some innocuos redirection, Bob only ever sees `https://priv Once the JWT is set, Bob will be authorized for all other sites which are configured to use `https://lasso.oursites.com/validate` from the `auth_request` nginx module. -The next time Bob is forwarded to google for login, since he has already authorized the site it immediately forwards him back and sets the cookie and sends him on his merry way. Bob may not even notice that he logged in via lasso. +The next time Bob is forwarded to google for login, since he has already authorized the lasso OAuth app, Google immediately forwards him back and sets the cookie and sends him on his merry way. Bob may not even notice that he logged in via lasso. diff --git a/TODO.md b/TODO.md index c04a1471..5dc0409c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,65 +1,17 @@ -## questions for golang meetup - -* how do I populate the context with the return code for later logging? -* where should I put my pkgs? - -## TODO - -* aaronpk 2017-10-04 - ‎[15:46] ‎<‎aaronpk‎>‎ so, immediate feature request is to be able to whitelist specific email addresses instead of doing domain matching for users - - -* aaronpk - ‎[16:40] ‎<‎aaronpk‎>‎ sure! basically i want to redirect to https://indieauth.com instead of google auth - ‎[16:41] ‎<‎aaronpk‎>‎ and there's an endpoint there that the plugin can use to verify the auth code and get user info - ‎[16:44] ‎<‎aaronpk‎>‎ so being able to customize this URL or maybe even override some method to be ableto customize the handling of the verification https://github.com/bnfinet/lasso/blob/master/handlers/handlers.go#L313 - ‎[16:49] ‎<‎aaronpk‎>‎ here's the docs i was walking you through https://indieauth.com/developers - ‎[16:53] ‎<‎bfoote‎>‎ oh that's looks pretty straight forward - -* add config for oauth Enpoint - https://github.com/golang/oauth2/blob/master/github/github.go - if endpoing is ~= google then allow 'hd' and accomodate getting User info - * is user info for Oauth a standard form? Probably _no_. Going to need some interpreters. - -* create a special team for admins - -* look for the token in an "Authorization: bearer $TOKEN" header +# TODO * include static assets in binary https://github.com/shurcooL/vfsgen -* restapi - * `/api/validate` endpoint that *any* service can connect to that validates the `X-LASSO-TOKEN` header - -* add lastupdate to user, sites, team - * handle multiple domains * set the `Oauth2.config{RedirectURL}` Google callback URL dynamically based on the domain that was offered - * iterate through a list of authorized domains * 302 redirect to the next domain * set a jwt cookie into each domain * might slow down login -* how to handle "not authorized for domain"? - * can nginx pass a 302 back to /login with an argument in the querystring such as.. - /login?jwt=$COOKIE - yes it can! using the auth_request_set $variable value; - `auth_request_set $auth_lasso_redirect $upstream_http_lasso_redirect` - http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request_set - * but we're forgetting about the round trip from the state login and setting the cookie - * we just need to detect if we've been here several times in a row, using state and then provide some kind of auth error - * try three times, then provide auth error - - * issue tokens manually for webhooks - * any of these are valid.. - * http cookie contents - * X-Lasso-Token: ${TOKEN} - * Authorization: Bearer ${TOKEN} - * ?lasso-token=${TOKEN} - * TODO is this the order that these are evaluated in? * tokens are special * set the "issuer" field to the user * does user exist? @@ -76,23 +28,42 @@ * pobably yes * how do we validate the token -* if the user is forwarded to /login a few times, we need to provide some explanation, and offer them an escaltion path or some way forward - * move binaries under a cmd/ subdirectory + * user management * twitter bootstrap * js build environment -* Docker container that's not Dockerfile.fromscratch -* graphviz of Bob visit flow + * additional validations (like what?) ## DONE +* add lastupdate to user, sites, team + +* if the user is forwarded to /login a few times, we need to provide some explanation, and offer them an escaltion path or some way forward + +* `/validate` endpoint that *any* service can connect to that validates the `X-LASSO-TOKEN` header + * any of these are valid.. + * http cookie contents + * X-Lasso-Token: ${TOKEN} + * Authorization: Bearer ${TOKEN} + * ?lasso-token=${TOKEN} + * set X-Lasso-User header passed through to the backend app https://stackoverflow.com/questions/19366215/setting-headers-with-nginx-auth-request-proxy#19366411 * replace gin.Cookie with gorilla.cookie +* how to handle "not authorized for domain"? + * can nginx pass a 302 back to /login with an argument in the querystring such as.. + /login?jwt=$COOKIE + yes it can! using the auth_request_set $variable value; + `auth_request_set $auth_lasso_redirect $upstream_http_lasso_redirect` + http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request_set + * but we're forgetting about the round trip from the state login and setting the cookie + * we just need to detect if we've been here several times in a row, using state and then provide some kind of auth error + * try three times, then provide auth error + * optionally compress the cookie (gzip && base64) * use url.QueryEscape() instead of base64 https://golang.org/pkg/net/url/#QueryEscape, or maybe use QueryEscape after base64 * can we stuff all the user/sites into a 4093 byte cookie, or perhaps a cookie half that size to leave room for other cookies @@ -133,6 +104,11 @@ yes.. * issue jwt into a cookie for each domain using an image +* add config for oauth Enpoint + https://github.com/golang/oauth2/blob/master/github/github.go + if endpoing is ~= google then allow 'hd' and accomodate getting User info + * is user info for Oauth a standard form? Probably _no_. Going to need some interpreters. + ## leaving teams out of this for now /admin/domains domain rights @@ -149,7 +125,10 @@ * User -## TODO +## TODO web interface + +* restapi +* create a special team for admins * websocket api * `getusers` diff --git a/do.sh b/do.sh index 1c552444..227f49cb 100755 --- a/do.sh +++ b/do.sh @@ -26,15 +26,14 @@ gogo () { docker run --rm -i -t -v /var/run/docker.sock:/var/run/docker.sock -v ${SDIR}/go:/go --name gogo $GOIMAGE $* } -revproxy () { - /home/bfoote/files/docker/bnfinet/dockerfiles/bnfnet/lasso-nginx-test/run_docker.sh $* -} - dbuild () { docker build -f Dockerfile -t $IMAGE . } gobuildstatic () { + # TODO: this doesn't include the templates + # https://github.com/shurcooL/vfsgen + CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . } @@ -84,6 +83,7 @@ goget () { # install all the things go get -v ./... } + test () { # test all the things if [ -n "$*" ]; then @@ -93,28 +93,9 @@ test () { fi } -graphviz () { -# FILE=$1; shift; - FILE=lasso_flow.dot; - CMD="docker run - --rm - -it - -v $(pwd):/code - -w /code - --entrypoint dot - themarquee/graphviz - -T png - -o lasso_flow.png - $FILE -" - echo $CMD - ${CMD} - -} - DB=data/lasso_bolt.db browsebolt() { - ~/go/bin/boltbrowser $DB + ${GOPATH}/bin/boltbrowser $DB } usage() { @@ -122,14 +103,13 @@ usage() { usage: $0 run - go run main.go $0 build - go build + $0 goget - get all dependencies $0 dbuild - build docker container $0 drun [args] - run docker container $0 test [./pkg_test.go] - run go tests (defaults to all tests) - $0 revproxy - run an nginx reverseproxy for naga.bnf.net $0 browsebolt - browse the boltdb at ${DB} $0 gogo [gocmd] - run, build, any go cmd $0 watch [cmd]] - watch the $CWD for any change and re-reun the [cmd] - $0 graphviz - lasso_flow.dot --> lasso_flow.jpg do is like make @@ -140,7 +120,7 @@ EOF ARG=$1; shift; case "$ARG" in - 'run'|'build'|'browsebolt'|'dbuild'|'drun'|'revproxy'|'graphviz'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic') + 'run'|'build'|'browsebolt'|'dbuild'|'drun'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic') $ARG $* ;; 'godoc') diff --git a/lasso_flow.dot b/lasso_flow.dot deleted file mode 100644 index 50984fa4..00000000 --- a/lasso_flow.dot +++ /dev/null @@ -1,41 +0,0 @@ -# graphviz diagram - -digraph Lasso { - - compound=true; - ratio=fill; node[fontsize=24]; - splines=line; - - browse_to_private_site -> nginx_receive_request; - nginx_receive_request -> validate; - validate -> evaluate_jwt; - evaluate_jwt -> NOT_AUTH; - NOT_AUTH -> redirect_to_login; - redirect_to_login -> redirected_to_login; - redirected_to_login -> login; - login -> redirect_to_google_oauth; - redirect_to_google_oauth -> redirected_to_google_oauth - redirected_to_google_oauth -> google_oauth; - google_oauth -> redirect_to_authorize; - redirect_to_authorize -> authorize; - authorize -> confirm_state; - confirm_state -> state_confirmed; - state_confirmed -> redirect_to_original_url; - redirect_to_original_url -> browse_to_private_site; - - evaluate_jwt -> SUCCESS; - SUCCESS -> set_cookie; - set_cookie -> homepage; - - subgraph cluster_bob { label="Bob"; browse_to_private_site; set_cookie; redirected_to_login; redirected_to_google_oauth} - subgraph cluster_nginx { label="nginx"; nginx_receive_request; NOT_AUTH; SUCCESS; redirect_to_login;} - subgraph cluster_lasso { label="lasso - login.oursites.com"; validate; evaluate_jwt; login; redirect_to_google_oauth; authorize; state_confirmed;} - subgraph cluster_google { label="Google Login"; google_oauth; redirect_to_authorize; confirm_state;} - subgraph cluster_oursite { label="private.oursites.com"; homepage } - - { rank = same; browse_to_private_site; nginx_receive_request; validate; } - { rank = same; evaluate_jwt; NOT_AUTH; redirect_to_login; redirected_to_login;} - { rank = same; login; redirect_to_google_oauth; redirected_to_google_oauth; google_oauth;} - { rank = same; SUCCESS; homepage;} - -} \ No newline at end of file diff --git a/lasso_flow.png b/lasso_flow.png deleted file mode 100644 index fa3ee99dc6d872e49145b75cb60c55cbed534420..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176681 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 diff --git a/pkg/response/response.go b/pkg/response/response.go index ff7bfd8c..de744959 100644 --- a/pkg/response/response.go +++ b/pkg/response/response.go @@ -16,22 +16,20 @@ type CaptureWriter struct { func (w *CaptureWriter) Write(b []byte) (int, error) { if w.StatusCode == 0 { w.StatusCode = 200 - log.Debugf("set w.StatusCode %d", w.StatusCode) + log.Debugf("CaptureWriter.Write set w.StatusCode %d", w.StatusCode) } - log.Debugf("CaptureWriter.Write code %d", w.StatusCode) return w.ResponseWriter.Write(b) } // Header calls http.Writer.Header() func (w *CaptureWriter) Header() http.Header { - log.Debugf("CaptureWriter.Header code %d", w.StatusCode) return w.ResponseWriter.Header() } // WriteHeader calls http.Writer.WriteHeader(code) func (w *CaptureWriter) WriteHeader(code int) { w.StatusCode = code - log.Debugf("CaptureWriter.WriteHeader code %d", w.StatusCode) + log.Debugf("CaptureWriter.WriteHeader set w.StatusCode %d", w.StatusCode) w.ResponseWriter.WriteHeader(code) } From f179ea2a6ed4d9518658d9ff36954ef9fdbc5e65 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 13:11:41 -0700 Subject: [PATCH 059/736] return only "200 OK" if authorized, unless we are testing --- handlers/handlers.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 9fec9578..1dd8145e 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -186,13 +186,16 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } } - // renderIndex(w, "user found from email "+user.Email) w.Header().Add(cfg.Cfg.Headers.User, claims.Username) w.Header().Add(cfg.Cfg.Headers.Success, "true") log.WithFields(log.Fields{cfg.Cfg.Headers.User: w.Header().Get(cfg.Cfg.Headers.User)}).Debug("response header") // good to go!! - ok200(w, r) + if cfg.Cfg.Testing { + renderIndex(w, "user authorized "+claims.Username) + } else { + ok200(w, r) + } // TODO // parse the jwt and see if the claim is valid for the domain From f8ccf865a1ccfde7ccd8d86b8bddb68e3abce3ea Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 13:27:25 -0700 Subject: [PATCH 060/736] write 200 OK in response body --- handlers/handlers.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 1dd8145e..b3502442 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -579,10 +579,8 @@ func redirect302(w http.ResponseWriter, r *http.Request, rURL string) { } func ok200(w http.ResponseWriter, r *http.Request) { - - n, err := w.Write(nil) + _, err := w.Write([]byte("200 OK\n")) if err != nil { log.Error(err) } - log.Debugf("ok200 with empty body (bytes %d)", n) } From 7585d535933435ec2d04206d61b3e6b6277ffda5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Oct 2018 15:42:55 -0700 Subject: [PATCH 061/736] modify example for ssl/443 and move error401 --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 03f76f80..e51794d1 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,15 @@ For support please file tickets here or visit our IRC channel [#lasso](irc://fre ```{.nginxconf} server { - listen 80 default_server; + listen 443 ssl http2; server_name dev.yourdomain.com; root /var/www/html/; + ssl_certificate /etc/letsencrypt/live/dev.yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/dev.yourdomain.com/privkey.pem; + # send all requests to the `/validate` endpoint for authorization auth_request /validate; - # if validate returns `401 not authorized` then forward the request to the error401block - error_page 401 = @error401; location = /validate { # lasso can run behind the same nginx-revproxy @@ -44,6 +45,9 @@ server { auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount; } + # if validate returns `401 not authorized` then forward the request to the error401block + error_page 401 = @error401; + location @error401 { # redirect to lasso for login return 302 https://lasso.yourdomain.com:9090/login?url=$scheme://$http_host$request_uri&lasso-failcount=$auth_resp_failcount&X-Lasso-Token=$auth_resp_jwt&error=$auth_resp_err; From 0601bea0c787d6e67971aa06e771210864f7771f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 3 Nov 2018 11:51:56 -0700 Subject: [PATCH 062/736] add version and semver to binary and display at startup --- Dockerfile | 7 +++++-- do.sh | 4 ++-- main.go | 10 +++++++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9a74f289..eac1aa29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,13 +2,16 @@ # https://github.com/LassoProject/lasso FROM golang:1.8 +LABEL maintainer="lasso@bnf.net" + RUN mkdir -p ${GOPATH}/src/github.com/LassoProject/lasso WORKDIR ${GOPATH}/src/github.com/LassoProject/lasso COPY . . -RUN go-wrapper download # "go get -d -v ./..." -RUN go-wrapper install # "go install -v ./..." +RUN go-wrapper download # "go get -d -v ./..." \ + && go-wrapper build # "go install -v ./..." \ + && ./do.sh build # see `do.sh` for lasso build details RUN rm -rf ./config ./data \ && ln -s /config ./config \ diff --git a/do.sh b/do.sh index 227f49cb..3c542890 100755 --- a/do.sh +++ b/do.sh @@ -8,7 +8,7 @@ cd $SDIR export LASSO_ROOT=${GOPATH}/src/github.com/LassoProject/lasso/ -IMAGE=bfoote/lasso +IMAGE=lassoproject/lasso GOIMAGE=golang:1.8 NAME=lasso HTTPPORT=9090 @@ -19,7 +19,7 @@ run () { } build () { - go build . + go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" . } gogo () { diff --git a/main.go b/main.go index 64ce5d3a..9128ff55 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,11 @@ import ( tran "github.com/LassoProject/lasso/pkg/transciever" ) +// version ang semver get overwritten by build with +// go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" +var version = "undefined" +var semver = "undefined" + func main() { log.Info("starting lasso") mux := http.NewServeMux() @@ -46,7 +51,10 @@ func main() { // http.Handle("/socket.io/", tran.Server) var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) - log.Infof("running lasso on %s", listen) + log.WithFields(log.Fields{ + "semver": semver, + "version": version, + "listen": listen}).Info("running lasso") srv := &http.Server{ Handler: mux, From 32619ae7bce33f8af03ed7f097d4b3beef48f24e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 3 Nov 2018 16:56:05 -0700 Subject: [PATCH 063/736] test for tcp port availability at startup, set branding --- handlers/handlers.go | 2 +- pkg/cfg/cfg.go | 105 +++++++++++++++++++++++++++---------------- pkg/cfg/cfg_test.go | 2 +- 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index b3502442..db0e1fb6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -330,7 +330,7 @@ func VerifyUser(u interface{}) (ok bool, err error) { } } } else if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { - err = fmt.Errorf("Email %s is not within a lasso managed domain", user.Email) + err = fmt.Errorf("Email %s is not within a "+cfg.Branding.+" managed domain", user.Email) // } else if !domains.IsUnderManagement(user.HostDomain) { // err = fmt.Errorf("HostDomain %s is not within a lasso managed domain", u.HostDomain) } else { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index e7cc544a..5597e1b5 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -5,7 +5,9 @@ import ( "flag" "io/ioutil" "math/rand" + "net" "os" + "strconv" "time" log "github.com/Sirupsen/logrus" @@ -78,7 +80,16 @@ type OAuthProviders struct { OIDC string } +type branding struct { + LCName string // lower case + UCName string // upper case + CcName string // camel case +} + var ( + // Branding that's our name + Branding = branding{"lasso", "LASSO", "Lasso"} + // Cfg the main exported config variable Cfg config @@ -118,6 +129,18 @@ func init() { } setDefaults() + + errT := BasicTest() + if errT != nil { + // log.Fatalf(errT.Error()) + panic(errT) + } + + var listen = Cfg.Listen + ":" + strconv.Itoa(Cfg.Port) + if !isTCPPortAvailable(listen) { + log.Fatal(errors.New("check the port availability (is " + Branding.CcName + " already running?)")) + } + log.Debug(viper.AllSettings()) } @@ -126,18 +149,13 @@ func ParseConfig() { log.Debug("opening config") viper.SetConfigName("config") viper.SetConfigType("yaml") - viper.AddConfigPath(os.Getenv("LASSO_ROOT") + "config") + viper.AddConfigPath(os.Getenv(Branding.UCName+"_ROOT") + "config") err := viper.ReadInConfig() // Find and read the config file if err != nil { // Handle errors reading the config file log.Fatalf("Fatal error config file: %s", err.Error()) panic(err) } - UnmarshalKey("lasso", &Cfg) - errT := BasicTest() - if errT != nil { - // log.Fatalf(err.prob) - panic(errT) - } + UnmarshalKey(Branding.LCName, &Cfg) // don't log the secret! // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) } @@ -170,89 +188,89 @@ func setDefaults() { // https://github.com/spf13/viper/issues/309 // viper.SetDefault("listen", "0.0.0.0") // viper.SetDefault(Cfg.Port, 9090) - // viper.SetDefault("Headers.SSO", "X-Lasso-Token") - // viper.SetDefault("Headers.Redirect", "X-Lasso-Requested-URI") + // viper.SetDefault("Headers.SSO", "X-"+Branding.CcName+"-Token") + // viper.SetDefault("Headers.Redirect", "X-"+Branding.CcName+"-Requested-URI") // viper.SetDefault("Cookie.Name", "Lasso") // logging - if !viper.IsSet("lasso.logLevel") { + if !viper.IsSet(Branding.LCName + ".logLevel") { Cfg.LogLevel = "info" } // network defaults - if !viper.IsSet("lasso.listen") { + if !viper.IsSet(Branding.LCName + ".listen") { Cfg.Listen = "0.0.0.0" } - if !viper.IsSet("lasso.port") { + if !viper.IsSet(Branding.LCName + ".port") { Cfg.Port = 9090 } - if !viper.IsSet("lasso.allowAllUsers") { + if !viper.IsSet(Branding.LCName + ".allowAllUsers") { Cfg.AllowAllUsers = false } - if !viper.IsSet("lasso.publicAccess") { + if !viper.IsSet(Branding.LCName + ".publicAccess") { Cfg.PublicAccess = false } // jwt defaults - if !viper.IsSet("lasso.jwt.secret") { + if !viper.IsSet(Branding.LCName + ".jwt.secret") { Cfg.JWT.Secret = getOrGenerateJWTSecret() } - if !viper.IsSet("lasso.jwt.issuer") { - Cfg.JWT.Issuer = "Lasso" + if !viper.IsSet(Branding.LCName + ".jwt.issuer") { + Cfg.JWT.Issuer = Branding.CcName } - if !viper.IsSet("lasso.jwt.maxAge") { + if !viper.IsSet(Branding.LCName + ".jwt.maxAge") { Cfg.JWT.MaxAge = 240 } - if !viper.IsSet("lasso.jwt.compress") { + if !viper.IsSet(Branding.LCName + ".jwt.compress") { Cfg.JWT.Compress = true } // cookie defaults - if !viper.IsSet("lasso.cookie.name") { + if !viper.IsSet(Branding.LCName + ".cookie.name") { Cfg.Cookie.Name = "LassoCookie" } - if !viper.IsSet("lasso.cookie.secure") { + if !viper.IsSet(Branding.LCName + ".cookie.secure") { Cfg.Cookie.Secure = false } - if !viper.IsSet("lasso.cookie.httpOnly") { + if !viper.IsSet(Branding.LCName + ".cookie.httpOnly") { Cfg.Cookie.HTTPOnly = true } // headers defaults - if !viper.IsSet("lasso.headers.jwt") { - Cfg.Headers.JWT = "X-Lasso-Token" + if !viper.IsSet(Branding.LCName + ".headers.jwt") { + Cfg.Headers.JWT = "X-" + Branding.CcName + "-Token" } - if !viper.IsSet("lasso.headers.querystring") { + if !viper.IsSet(Branding.LCName + ".headers.querystring") { Cfg.Headers.QueryString = "access_token" } - if !viper.IsSet("lasso.headers.redirect") { - Cfg.Headers.Redirect = "X-Lasso-Requested-URI" + if !viper.IsSet(Branding.LCName + ".headers.redirect") { + Cfg.Headers.Redirect = "X-" + Branding.CcName + "-Requested-URI" } - if !viper.IsSet("lasso.headers.user") { - Cfg.Headers.User = "X-Lasso-User" + if !viper.IsSet(Branding.LCName + ".headers.user") { + Cfg.Headers.User = "X-" + Branding.CcName + "-User" } - if !viper.IsSet("lasso.headers.success") { - Cfg.Headers.Success = "X-Lasso-Success" + if !viper.IsSet(Branding.LCName + ".headers.success") { + Cfg.Headers.Success = "X-" + Branding.CcName + "-Success" } // db defaults - if !viper.IsSet("lasso.db.file") { - Cfg.DB.File = "data/lasso_bolt.db" + if !viper.IsSet(Branding.LCName + ".db.file") { + Cfg.DB.File = "data/" + Branding.LCName + "_bolt.db" } // session HERE - if !viper.IsSet("lasso.session.name") { - Cfg.Session.Name = "lassoSession" + if !viper.IsSet(Branding.LCName + ".session.name") { + Cfg.Session.Name = Branding.LCName + "Session" } // testing convenience variable - if !viper.IsSet("lasso.testing") { + if !viper.IsSet(Branding.LCName + ".testing") { Cfg.Testing = false } - if viper.IsSet("lasso.test_url") { + if viper.IsSet(Branding.LCName + ".test_url") { Cfg.TestURLs = append(Cfg.TestURLs, Cfg.TestURL) } // TODO: proably change this name, maybe set the domain/port the webapp runs on - if !viper.IsSet("lasso.webapp") { + if !viper.IsSet(Branding.LCName + ".webapp") { Cfg.WebApp = false } @@ -351,3 +369,14 @@ func getOrGenerateJWTSecret() string { } return string(b) } + +func isTCPPortAvailable(listen string) bool { + log.Debug("checking availability of tcp port: " + listen) + conn, err := net.Listen("tcp", listen) + if err != nil { + log.Error(err) + return false + } + conn.Close() + return true +} diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index a19726b2..4b4734a0 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -18,7 +18,7 @@ func init() { func TestConfigParsing(t *testing.T) { - UnmarshalKey("lasso", &cfg) + UnmarshalKey(Branding.LCName, &cfg) log.Debugf("cfgPort %d", cfg.Port) log.Debugf("cfgDomains %s", cfg.Domains[0]) From f8f3848905dee52a857d195a32b37c83b1785a81 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 3 Nov 2018 16:57:03 -0700 Subject: [PATCH 064/736] use go 1.10, include branch semver build info into binary --- Dockerfile | 12 ++++++++---- do.sh | 16 +++++++++++++--- main.go | 31 ++++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index eac1aa29..39474ede 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # lassoproject/lasso # https://github.com/LassoProject/lasso -FROM golang:1.8 +FROM golang:1.10 LABEL maintainer="lasso@bnf.net" @@ -9,9 +9,13 @@ WORKDIR ${GOPATH}/src/github.com/LassoProject/lasso COPY . . -RUN go-wrapper download # "go get -d -v ./..." \ - && go-wrapper build # "go install -v ./..." \ - && ./do.sh build # see `do.sh` for lasso build details +# RUN go-wrapper download # "go get -d -v ./..." +# RUN ./do.sh build # see `do.sh` for lasso build details +# RUN go-wrapper install # "go install -v ./..." + +RUN go get -d -v ./... +RUN ./do.sh build # see `do.sh` for lasso build details +RUN ./do.sh install RUN rm -rf ./config ./data \ && ln -s /config ./config \ diff --git a/do.sh b/do.sh index 3c542890..eac3d498 100755 --- a/do.sh +++ b/do.sh @@ -9,7 +9,7 @@ cd $SDIR export LASSO_ROOT=${GOPATH}/src/github.com/LassoProject/lasso/ IMAGE=lassoproject/lasso -GOIMAGE=golang:1.8 +GOIMAGE=golang:1.10 NAME=lasso HTTPPORT=9090 GODOC_PORT=5050 @@ -19,7 +19,16 @@ run () { } build () { - go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" . + local VERSION=$(git describe --always --long) + local DT=$(date --rfc-3339=seconds --universal| sed 's/ /T/') + local FQDN=$(hostname --fqdn) + local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) + local BRANCH=$(git rev-parse --abbrev-ref HEAD) + go build -i -v -ldflags=" -X main.version=${VERSION} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . +} + +install () { + cp ./lasso ${GOPATH}/bin/lasso } gogo () { @@ -103,6 +112,7 @@ usage() { usage: $0 run - go run main.go $0 build - go build + $0 install - move binary to ${GOPATH}/bin/lasso $0 goget - get all dependencies $0 dbuild - build docker container $0 drun [args] - run docker container @@ -120,7 +130,7 @@ EOF ARG=$1; shift; case "$ARG" in - 'run'|'build'|'browsebolt'|'dbuild'|'drun'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic') + 'run'|'build'|'browsebolt'|'dbuild'|'drun'|'install'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic') $ARG $* ;; 'godoc') diff --git a/main.go b/main.go index 9128ff55..adc9e69e 100644 --- a/main.go +++ b/main.go @@ -18,11 +18,30 @@ import ( // version ang semver get overwritten by build with // go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" -var version = "undefined" -var semver = "undefined" + +var ( + version = "undefined" + builddt = "undefined" + host = "undefined" + semver = "undefined" + branch = "undefined" +) + +func init() { + // var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) +} func main() { - log.Info("starting lasso") + var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) + log.WithFields(log.Fields{ + // "semver": semver, + "version": version, + "buildtime": builddt, + "buildhost": host, + "branch": branch, + "semver": semver, + "listen": listen}).Info("starting " + cfg.Branding) + mux := http.NewServeMux() authH := http.HandlerFunc(handlers.ValidateRequestHandler) @@ -50,12 +69,6 @@ func main() { // mux.Handle("/socket.io/", cors.AllowAll(socketio)) // http.Handle("/socket.io/", tran.Server) - var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) - log.WithFields(log.Fields{ - "semver": semver, - "version": version, - "listen": listen}).Info("running lasso") - srv := &http.Server{ Handler: mux, Addr: listen, From 69bb1e9350f2a8244f80c063bb375aa1c526c096 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 3 Nov 2018 17:04:36 -0700 Subject: [PATCH 065/736] set branding --- handlers/handlers.go | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index db0e1fb6..185a1f5d 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -330,7 +330,7 @@ func VerifyUser(u interface{}) (ok bool, err error) { } } } else if len(cfg.Cfg.Domains) != 0 && !domains.IsUnderManagement(user.Email) { - err = fmt.Errorf("Email %s is not within a "+cfg.Branding.+" managed domain", user.Email) + err = fmt.Errorf("Email %s is not within a "+cfg.Branding.CcName+" managed domain", user.Email) // } else if !domains.IsUnderManagement(user.HostDomain) { // err = fmt.Errorf("HostDomain %s is not within a lasso managed domain", u.HostDomain) } else { diff --git a/main.go b/main.go index adc9e69e..f0b49bf8 100644 --- a/main.go +++ b/main.go @@ -40,7 +40,7 @@ func main() { "buildhost": host, "branch": branch, "semver": semver, - "listen": listen}).Info("starting " + cfg.Branding) + "listen": listen}).Info("starting " + cfg.Branding.CcName) mux := http.NewServeMux() From b1d75f3ea6147c45683b4f81604f69f70b3f2f4a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 3 Nov 2018 17:18:28 -0700 Subject: [PATCH 066/736] tell the end user that they're in testing mode --- handlers/handlers.go | 3 ++- templates/index.tmpl | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 185a1f5d..d407de95 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -28,6 +28,7 @@ import ( type Index struct { Msg string TestURLs []string + Testing bool } // AuthError sets the values to return to nginx @@ -301,7 +302,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { } func renderIndex(w http.ResponseWriter, msg string) { - if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURLs: cfg.Cfg.TestURLs}); err != nil { + if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURLs: cfg.Cfg.TestURLs, Testing: cfg.Cfg.Testing}); err != nil { log.Error(err) } } diff --git a/templates/index.tmpl b/templates/index.tmpl index 31ba1acc..11fd6147 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -6,7 +6,10 @@ Lasso: {{ .Msg }}. - +{{ if .Testing }} +

    -- test mode --

    +config file includes testing: true +{{ end }}

    {{ .Msg }}.

    {{ end }} - +
    For support, please contact your network administrator or whomever configured Nginx to use Vouch Proxy.

    For help with Vouch Proxy or to file a bug report, please visit https://github.com/vouch/vouch-proxy

    +

    From cddeb58d817ae63376f3a26d973b89fae3338c1e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 19 May 2020 10:10:43 -0700 Subject: [PATCH 412/736] #132 set defaults from .defaults.yml --- config/.defaults.yml | 68 ++++++++++++++++++++++++++++ pkg/cfg/cfg.go | 104 +++---------------------------------------- 2 files changed, 75 insertions(+), 97 deletions(-) create mode 100644 config/.defaults.yml diff --git a/config/.defaults.yml b/config/.defaults.yml new file mode 100644 index 00000000..8238c4e0 --- /dev/null +++ b/config/.defaults.yml @@ -0,0 +1,68 @@ +# default values for Vouch Proxy +# this is related to Env Vars +# https://github.com/vouch/vouch-proxy/issues/132 +# https://github.com/vouch/vouch-proxy/pull/134 + +# you don't want to mess with these +vouch: + logLevel: info + testing: false + listen: 0.0.0.0 + port: 9090 + domains: + - + allowAllUsers: false + publicAccess: false + whiteList: + teamWhitelist: + + jwt: + secret: + issuer: Vouch + maxAge: 240 + compress: true + + cookie: + name: VouchCookie + domain: + secure: true + httpOnly: true + maxAge: 240 + sameSite: + + session: + name: VouchSession + key: + + headers: + jwt: X-Vouch-Token + user: X-Vouch-User + success: X-Vouch-Success + error: X-Vouch-Error + querystring: access_token + redirect: X-Vouch-Requested-URI + claims: + - + claimheader: X-Vouch-IdP-Claims- + accesstoken: X-Vouch-IdP-AccessToken + idtoken: X-Vouch-IdP-IdToken + test_url: + post_logout_redirect_uris: + - + +oauth: + provider: + # create new credentials at: + # https://console.developers.google.com/apis/credentials + client_id: + client_secret: + callback_url: + callback_urls: + - + preferredDomain: yourdomain.com + auth_url: + token_url: + user_info_url: + end_session_endpoint: + scopes: + - diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index d80dfd4d..04eb9e9d 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -350,110 +350,20 @@ func basicTest() error { // setDefaults set default options for most items func setDefaults() { - // this should really be done by Viper up in parseConfig but.. - // nested defaults is currently *broken* - // https://github.com/spf13/viper/issues/309 - // viper.SetDefault("listen", "0.0.0.0") - // viper.SetDefault(Cfg.Port, 9090) - // viper.SetDefault("Headers.SSO", "X-"+Branding.CcName+"-Token") - // viper.SetDefault("Headers.Redirect", "X-"+Branding.CcName+"-Requested-URI") - // viper.SetDefault("Cookie.Name", "Vouch") - - // network defaults - if !viper.IsSet(Branding.LCName + ".listen") { - Cfg.Listen = "0.0.0.0" - } - - if !viper.IsSet(Branding.LCName + ".port") { - Cfg.Port = 9090 + viper.SetConfigName(".defaults") + viper.SetConfigType("yaml") + viper.AddConfigPath(filepath.Join(RootDir, "config")) + viper.ReadInConfig() + if err := viper.UnmarshalKey(Branding.LCName, &Cfg); err != nil { + log.Error(err) } + log.Debugf("setDefaults from .defaults.yml %+v", Cfg) // bare minimum for healthcheck achieved if *CmdLine.IsHealthCheck { return } - if !viper.IsSet(Branding.LCName + ".allowAllUsers") { - Cfg.AllowAllUsers = false - } - if !viper.IsSet(Branding.LCName + ".publicAccess") { - Cfg.PublicAccess = false - } - - // jwt defaults - if !viper.IsSet(Branding.LCName + ".jwt.secret") { - Cfg.JWT.Secret = getOrGenerateJWTSecret() - } - if !viper.IsSet(Branding.LCName + ".jwt.issuer") { - Cfg.JWT.Issuer = Branding.CcName - } - if !viper.IsSet(Branding.LCName + ".jwt.maxAge") { - Cfg.JWT.MaxAge = 240 - } - if !viper.IsSet(Branding.LCName + ".jwt.compress") { - Cfg.JWT.Compress = true - } - - // cookie defaults - if !viper.IsSet(Branding.LCName + ".cookie.name") { - Cfg.Cookie.Name = Branding.CcName + "Cookie" - } - if !viper.IsSet(Branding.LCName + ".cookie.secure") { - Cfg.Cookie.Secure = false - } - if !viper.IsSet(Branding.LCName + ".cookie.httpOnly") { - Cfg.Cookie.HTTPOnly = true - } - if !viper.IsSet(Branding.LCName + ".cookie.maxAge") { - Cfg.Cookie.MaxAge = Cfg.JWT.MaxAge - } else { - // it is set! is it bigger than jwt.maxage? - if Cfg.Cookie.MaxAge > Cfg.JWT.MaxAge { - log.Warnf("setting `%s.cookie.maxage` to `%s.jwt.maxage` value of %d minutes (curently set to %d minutes)", Branding.LCName, Branding.LCName, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge) - Cfg.Cookie.MaxAge = Cfg.JWT.MaxAge - } - } - - // headers defaults - if !viper.IsSet(Branding.LCName + ".headers.jwt") { - Cfg.Headers.JWT = "X-" + Branding.CcName + "-Token" - } - if !viper.IsSet(Branding.LCName + ".headers.querystring") { - Cfg.Headers.QueryString = "access_token" - } - if !viper.IsSet(Branding.LCName + ".headers.redirect") { - Cfg.Headers.Redirect = "X-" + Branding.CcName + "-Requested-URI" - } - if !viper.IsSet(Branding.LCName + ".headers.user") { - Cfg.Headers.User = "X-" + Branding.CcName + "-User" - } - if !viper.IsSet(Branding.LCName + ".headers.success") { - Cfg.Headers.Success = "X-" + Branding.CcName + "-Success" - } - if !viper.IsSet(Branding.LCName + ".headers.claimheader") { - Cfg.Headers.ClaimHeader = "X-" + Branding.CcName + "-IdP-Claims-" - } - - // session - if !viper.IsSet(Branding.LCName + ".session.name") { - Cfg.Session.Name = Branding.CcName + "Session" - } - if !viper.IsSet(Branding.LCName + ".session.key") { - log.Warn("generating random session.key") - rstr, err := securerandom.Base64OfBytes(base64Bytes) - if err != nil { - log.Fatal(err) - } - Cfg.Session.Key = rstr - } - - // testing convenience variable - if !viper.IsSet(Branding.LCName + ".testing") { - Cfg.Testing = false - } - if viper.IsSet(Branding.LCName + ".test_url") { - Cfg.TestURLs = append(Cfg.TestURLs, Cfg.TestURL) - } } func claimToHeader(claim string) (string, error) { From 199d3996e62ec9c52f2015a35797a2e1bafa45fe Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 19 May 2020 10:11:18 -0700 Subject: [PATCH 413/736] configurable X-Vouch-Error --- pkg/responses/responses.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 1083e53b..55cf8593 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -85,7 +85,7 @@ func Redirect302(w http.ResponseWriter, r *http.Request, rURL string) { func Error400(w http.ResponseWriter, r *http.Request, e error) { log.Error(e) cookie.ClearCookie(w, r) - w.Header().Set("X-Vouch-Error", e.Error()) + w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusBadRequest) RenderError(w, "400 Bad Request") } @@ -95,7 +95,7 @@ func Error400(w http.ResponseWriter, r *http.Request, e error) { func Error401(w http.ResponseWriter, r *http.Request, e error) { log.Error(e) cookie.ClearCookie(w, r) - w.Header().Set("X-Vouch-Error", e.Error()) + w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) http.Error(w, e.Error(), http.StatusUnauthorized) // RenderError(w, "401 Unauthorized") } @@ -105,7 +105,7 @@ func Error401(w http.ResponseWriter, r *http.Request, e error) { func Error403(w http.ResponseWriter, r *http.Request, e error) { log.Error(e) cookie.ClearCookie(w, r) - w.Header().Set("X-Vouch-Error", e.Error()) + w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusForbidden) RenderError(w, "403 Forbidden") } From f469404a5241f2abf630e841870e45ea6c671eb6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 19 May 2020 10:23:08 -0700 Subject: [PATCH 414/736] fix #132 configuration via env var --- pkg/cfg/cfg.go | 177 ++++++++++++++++++++++++++++---------------- pkg/cfg/cfg_test.go | 149 +++++++++++++++++++++++++++++++++++++ pkg/cfg/oauth.go | 27 +++---- 3 files changed, 277 insertions(+), 76 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 04eb9e9d..3986f10a 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -19,8 +19,8 @@ import ( "path/filepath" "strings" + "github.com/kelseyhightower/envconfig" "github.com/mitchellh/mapstructure" - "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" "go.uber.org/zap" @@ -28,6 +28,11 @@ import ( ) // Config vouch jwt cookie configuration +// Note to developers! Any new config elements +// should use `snake_case` such as `post_logout_redirect_uris` +// in certain situations you'll need to add both a `mapstructure` tag used by viper +// as well as a `envconfig` tag used by https://github.com/kelseyhightower/envconfig +// though most of the time envconfig will use the struct key's name: VOUCH_PORT VOUCH_JWT_MAXAGE type Config struct { LogLevel string `mapstructure:"logLevel"` Listen string `mapstructure:"listen"` @@ -58,6 +63,7 @@ type Config struct { QueryString string `mapstructure:"querystring"` Redirect string `mapstructure:"redirect"` Success string `mapstructure:"success"` + Error string `mapstructure:"error"` ClaimHeader string `mapstructure:"claimheader"` Claims []string `mapstructure:"claims"` AccessToken string `mapstructure:"accesstoken"` @@ -71,21 +77,20 @@ type Config struct { TestURL string `mapstructure:"test_url"` TestURLs []string `mapstructure:"test_urls"` Testing bool `mapstructure:"testing"` - LogoutRedirectURLs []string `mapstructure:"post_logout_redirect_uris"` + LogoutRedirectURLs []string `mapstructure:"post_logout_redirect_uris" envconfig:"post_logout_redirect_uris"` } type branding struct { - LCName string // lower case - UCName string // upper case - CcName string // camel case - FullName string // Vouch Proxy - OldLCName string // lasso - URL string // https://github.com/vouch/vouch-proxy + LCName string // lower case vouch + UCName string // UPPER CASE VOUCH + CcName string // camelCase Vouch + FullName string // Vouch Proxy + URL string // https://github.com/vouch/vouch-proxy } var ( // Branding that's our name - Branding = branding{"vouch", "VOUCH", "Vouch", "Vouch Proxy", "lasso", "https://github.com/vouch/vouch-proxy"} + Branding = branding{"vouch", "VOUCH", "Vouch", "Vouch Proxy", "https://github.com/vouch/vouch-proxy"} // RequiredOptions must have these fields set for minimum viable config RequiredOptions = []string{"oauth.provider", "oauth.client_id"} @@ -126,6 +131,15 @@ const ( ) // Configure called at the very top of main() +// the order of config follows the Viper conventions... +// +// The priority of the sources is the following: +// 1. comand line flags +// 2. env. variables +// 3. config file +// 4. defaults +// +// so we process these in backwards order (defaults then config file) func Configure() { Logging.configureFromCmdline() @@ -140,9 +154,16 @@ func Configure() { return } - parseConfig() - Logging.configure() setDefaults() + parseConfigFile() + // configureFromEnvVars() + configureFromEnv() + + fixConfigOptions() + Logging.configure() + if err := configureOauth(); err == nil { + setProviderDefaults() + } cleanClaimsHeaders() if *CmdLine.port != -1 { Cfg.Port = *CmdLine.port @@ -150,6 +171,20 @@ func Configure() { } +// using envconfig +// https://github.com/kelseyhightower/envconfig +func configureFromEnv() { + err := envconfig.Process(Branding.UCName, Cfg) + if err != nil { + log.Fatal(err.Error()) + } + err = envconfig.Process("OAUTH", GenOAuth) + if err != nil { + log.Fatal(err.Error()) + } + +} + // ValidateConfiguration confirm the Configuration is valid func ValidateConfiguration() { if Cfg.Testing { @@ -180,45 +215,8 @@ func setRootDir() { } } -// InitForTestPurposes is called by most *_testing.go files in Vouch Proxy -func InitForTestPurposes() { - InitForTestPurposesWithProvider("") -} - -// InitForTestPurposesWithProvider just for testing -func InitForTestPurposesWithProvider(provider string) { - Cfg = &Config{} // clear it out since we're called multiple times from subsequent tests - Logging.setLogLevel(zapcore.WarnLevel) - setRootDir() - // _, b, _, _ := runtime.Caller(0) - // basepath := filepath.Dir(b) - configEnv := os.Getenv(Branding.UCName + "_CONFIG") - if configEnv == "" { - if err := os.Setenv(Branding.UCName+"_CONFIG", filepath.Join(RootDir, "config/testing/test_config.yml")); err != nil { - log.Error(err) - } - } - // Configure() - // setRootDir() - parseConfig() - if err := configureOauth(); err == nil { - setProviderDefaults() - } - - setDefaults() - // setDevelopmentLogger() - - // Needed to override the provider, which is otherwise set via yml - if provider != "" { - GenOAuth.Provider = provider - setProviderDefaults() - } - cleanClaimsHeaders() - -} - // parseConfig parse the config file -func parseConfig() { +func parseConfigFile() { configEnv := os.Getenv(Branding.UCName + "_CONFIG") if configEnv != "" { @@ -252,26 +250,40 @@ func parseConfig() { log.Error(err) } - if len(Cfg.Domains) == 0 { - // then lets check for "lasso" - var oldConfig = &Config{} - if err = UnmarshalKey(Branding.OldLCName, &oldConfig); err != nil { - log.Error(err) - } + // don't log the secret! + // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) +} - if len(oldConfig.Domains) != 0 { - log.Errorf(` +func fixConfigOptions() { -IMPORTANT! + if Cfg.Cookie.MaxAge > Cfg.JWT.MaxAge { + log.Warnf("setting `%s.cookie.maxage` to `%s.jwt.maxage` value of %d minutes (curently set to %d minutes)", Branding.LCName, Branding.LCName, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge) + Cfg.Cookie.MaxAge = Cfg.JWT.MaxAge + } + + // headers defaults + if !viper.IsSet(Branding.LCName + ".headers.redirect") { + Cfg.Headers.Redirect = "X-" + Branding.CcName + "-Requested-URI" + } -please update your config file to change '%s:' to '%s:' as per %s - `, Branding.OldLCName, Branding.LCName, Branding.URL) - Cfg = oldConfig + // jwt defaults + if len(Cfg.JWT.Secret) == 0 { + Cfg.JWT.Secret = getOrGenerateJWTSecret() + } + + if len(Cfg.Session.Key) == 0 { + log.Warn("generating random session.key") + rstr, err := securerandom.Base64OfBytes(base64Bytes) + if err != nil { + log.Fatal(err) } + Cfg.Session.Key = rstr + } + + if Cfg.TestURL != "" { + Cfg.TestURLs = append(Cfg.TestURLs, Cfg.TestURL) } - // don't log the secret! - // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) } // use viper and mapstructure check to see if @@ -418,3 +430,42 @@ func cleanClaimsHeaders() error { Cfg.Headers.ClaimsCleaned = cleanedHeaders return nil } + +// InitForTestPurposes is called by most *_testing.go files in Vouch Proxy +func InitForTestPurposes() { + InitForTestPurposesWithProvider("") +} + +// InitForTestPurposesWithProvider just for testing +func InitForTestPurposesWithProvider(provider string) { + Cfg = &Config{} // clear it out since we're called multiple times from subsequent tests + Logging.setLogLevel(zapcore.WarnLevel) + setRootDir() + // _, b, _, _ := runtime.Caller(0) + // basepath := filepath.Dir(b) + configEnv := os.Getenv(Branding.UCName + "_CONFIG") + if configEnv == "" { + if err := os.Setenv(Branding.UCName+"_CONFIG", filepath.Join(RootDir, "config/testing/test_config.yml")); err != nil { + log.Error(err) + } + } + // Configure() + // setRootDir() + setDefaults() + parseConfigFile() + configureFromEnv() + if err := configureOauth(); err == nil { + setProviderDefaults() + } + fixConfigOptions() + + // setDevelopmentLogger() + + // Needed to override the provider, which is otherwise set via yml + if provider != "" { + GenOAuth.Provider = provider + setProviderDefaults() + } + cleanClaimsHeaders() + +} diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 862a37ab..f8e69aed 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -11,6 +11,9 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( + "fmt" + "os" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -70,3 +73,149 @@ func Test_claimToHeader(t *testing.T) { }) } } + +func Test_configureFromEnvCfg(t *testing.T) { + + // each of these env vars holds a.. + // string + // get all the values + senv := []string{"VOUCH_LOGLEVEL", "VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", + "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", + "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", + "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY"} + // array of strings + saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} + // int + ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE"} + // bool + benv := []string{"VOUCH_ALLOWALLUSERS", "VOUCH_PUBLICACCESS", "VOUCH_JWT_COMPRESS", "VOUCH_COOKIE_SECURE", + "VOUCH_COOKIE_HTTPONLY", "VOUCH_TESTING"} + + // populate environmental variables + svalue := "svalue" + for _, v := range senv { + os.Setenv(v, svalue) + } + savalue := []string{"arrayone", "arraytwo", "arraythree"} + for _, v := range saenv { + os.Setenv(v, strings.Join(savalue, ",")) + t.Logf("savalue: %s", savalue) + } + ivalue := 1234 + for _, v := range ienv { + os.Setenv(v, fmt.Sprint(ivalue)) + } + bvalue := false + for _, v := range benv { + os.Setenv(v, fmt.Sprint(bvalue)) + } + + // run the thing + configureFromEnv() + scfg := []string{Cfg.LogLevel, Cfg.Listen, Cfg.JWT.Issuer, Cfg.JWT.Secret, Cfg.Headers.JWT, + Cfg.Headers.User, Cfg.Headers.QueryString, Cfg.Headers.Redirect, Cfg.Headers.Success, Cfg.Headers.Error, + Cfg.Headers.ClaimHeader, Cfg.Headers.AccessToken, Cfg.Headers.IDToken, Cfg.Cookie.Name, Cfg.Cookie.Domain, + Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, + } + + sacfg := [][]string{Cfg.Domains, Cfg.WhiteList, Cfg.TeamWhiteList, Cfg.Headers.Claims, Cfg.TestURLs, Cfg.LogoutRedirectURLs} + icfg := []int{Cfg.Port, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge} + bcfg := []bool{Cfg.AllowAllUsers, Cfg.PublicAccess, Cfg.JWT.Compress, + Cfg.Cookie.Secure, + Cfg.Cookie.HTTPOnly, + Cfg.Testing, + } + + tests := []struct { + name string + }{ + // TODO: Add test cases. + {"Cfg struct field should be populated from env var"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i, v := range scfg { + assert.Equal(t, svalue, v, fmt.Sprintf("%d: v is %s not %s", i, v, svalue)) + } + for _, v := range sacfg { + assert.Equal(t, savalue, v, "v is %+s not %+s", v, savalue) + } + for _, v := range icfg { + assert.Equal(t, ivalue, v, "v is %+s not %+s", v, ivalue) + } + for _, v := range bcfg { + assert.Equal(t, bvalue, v, "v is %+s not %+s", v, bvalue) + } + }) + } + + os.Clearenv() + os.Setenv(Branding.UCName+"_ROOT", RootDir) + +} + +func Test_configureFromEnvOAuth(t *testing.T) { + + // each of these env vars holds a.. + // string + // get all the values + senv := []string{ + "OAUTH_PROVIDER", "OAUTH_CLIENT_ID", "OAUTH_CLIENT_SECRET", "OAUTH_AUTH_URL", "OAUTH_TOKEN_URL", + "OAUTH_END_SESSION_ENDPOINT", "OAUTH_CALLBACK_URL", "OAUTH_USER_INFO_URL", "OAUTH_USER_TEAM_URL", "OAUTH_USER_ORG_URL", + "OAUTH_PREFERREDDOMAIN", + } + // array of strings + saenv := []string{"OAUTH_CALLBACK_URLS", "OAUTH_SCOPES"} + + // populate environmental variables + svalue := "svalue" + for _, v := range senv { + os.Setenv(v, svalue) + } + savalue := []string{"arrayone", "arraytwo", "arraythree"} + for _, v := range saenv { + os.Setenv(v, strings.Join(savalue, ",")) + t.Logf("savalue: %s", savalue) + } + + // run the thing + configureFromEnv() + + scfg := []string{ + GenOAuth.Provider, + GenOAuth.ClientID, + GenOAuth.ClientSecret, + GenOAuth.AuthURL, + GenOAuth.TokenURL, + GenOAuth.LogoutURL, + GenOAuth.RedirectURL, + GenOAuth.UserInfoURL, + GenOAuth.UserTeamURL, + GenOAuth.UserOrgURL, + GenOAuth.PreferredDomain, + } + sacfg := [][]string{ + GenOAuth.RedirectURLs, + GenOAuth.Scopes, + } + + tests := []struct { + name string + }{ + // TODO: Add test cases. + {"OAuth struct field should be populated from env var"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i, v := range scfg { + assert.Equal(t, svalue, v, fmt.Sprintf("%d: v is %s not %s", i, v, svalue)) + } + for i, v := range sacfg { + assert.Equal(t, savalue, v, fmt.Sprintf("%d: v is %s not %s", i, v, savalue)) + } + }) + } + os.Clearenv() + os.Setenv(Branding.UCName+"_ROOT", RootDir) + +} diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 00964e0e..421b85f1 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -22,9 +22,8 @@ import ( var ( // GenOAuth exported OAuth config variable - // TODO: I think GenOAuth and OAuthConfig can be combined! - // perhaps by https://golang.org/doc/effective_go.html#embedding - GenOAuth *oauthConfig + // TODO: GenOAuth and OAuthClient should be combined + GenOAuth = &oauthConfig{} // OAuthClient is the configured client which will call the provider // this actually carries the oauth2 client ala oauthclient.Client(oauth2.NoContext, providerToken) @@ -58,19 +57,21 @@ type OAuthProviders struct { } // oauth config items endoint for access +// `envconfig` tag is for env var support +// https://github.com/kelseyhightower/envconfig type oauthConfig struct { Provider string `mapstructure:"provider"` - ClientID string `mapstructure:"client_id"` - ClientSecret string `mapstructure:"client_secret"` - AuthURL string `mapstructure:"auth_url"` - TokenURL string `mapstructure:"token_url"` - LogoutURL string `mapstructure:"end_session_endpoint"` - RedirectURL string `mapstructure:"callback_url"` - RedirectURLs []string `mapstructure:"callback_urls"` + ClientID string `mapstructure:"client_id" envconfig:"client_id"` + ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` + AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` + TokenURL string `mapstructure:"token_url" envconfig:"token_url"` + LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` + RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` + RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url"` - UserTeamURL string `mapstructure:"user_team_url"` - UserOrgURL string `mapstructure:"user_org_url"` + UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` + UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` + UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` PreferredDomain string `mapstructure:"preferredDomain"` } From 8e61e2482cef1bee358152a8db463958b822c4e3 Mon Sep 17 00:00:00 2001 From: Jerry Chong Date: Thu, 21 May 2020 20:23:44 +0800 Subject: [PATCH 415/736] Fix typo (#267) "successflu" -> "successful" --- handlers/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/auth.go b/handlers/auth.go index f7682f23..62f91eec 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -62,7 +62,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { ptokens := structs.PTokens{} if err := getUserInfo(r, &user, &customClaims, &ptokens); err != nil { - responses.Error400(w, r, fmt.Errorf("/auth Error while retreiving user info after successflu login at the OAuth provider: %w", err)) + responses.Error400(w, r, fmt.Errorf("/auth Error while retreiving user info after successful login at the OAuth provider: %w", err)) return } log.Debugf("/auth Claims from userinfo: %+v", customClaims) From 8441da43ecfafa1ea63448b949e95d3863ea320d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 11:26:16 -0700 Subject: [PATCH 416/736] #132 document config via environmental variable --- README.md | 52 +++++++++++++++++++--- config/config.yml_example | 90 +++++++++++++++++++++++++-------------- 2 files changed, 105 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 82476ced..512ecf2d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Please do let us know when you have deployed Vouch Proxy with your preffered IdP If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be less than 1ms -## Installation +## Installation and Configuration Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L27-L29) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L68-L69) to `yourdomain.com`. @@ -135,11 +135,34 @@ server { } ``` -An example of using Vouch Proxy with Nginx cacheing of the proxied validation request is available in [issue #76](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743). +Additional Nginx configurations can be found in the [examples](https://github.com/vouch/vouch-proxy/tree/master/examples) directory. -If you're protecting an API with Vouch Proxy you may need to configure Nginx to handle `OPTIONS` requests in the `/validate` block [issue #216](https://github.com/vouch/vouch-proxy/issues/216). +## Configuring Vouch Proxy using Environmental Variables -Additional Nginx configurations can be found in the [examples](https://github.com/vouch/vouch-proxy/tree/master/examples) directory. +Here's a minimal setup using Google OAuth... + +```bash +VOUCH_DOMAINS=yourdomain.com \ + OAUTH_PROVIDER=google \ + OAUTH_CLIENT_ID=1234 \ + OAUTH_CLIENT_SECRET=secretsecret \ + OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \ + ./vouch-proxy +``` + +Environmental variable names are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) + +All lists with multiple values must be comma separated: `VOUCH_DOMAINS="yourdomain.com,yourotherdomain.com"` + +## More advanced configurations + +- [cacheing of the Vouch Proxy validation response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) +- [handleing `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) +- [validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) +- [running on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) +- [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) + +Please do help us to expand this list. ## Running from Docker @@ -151,9 +174,26 @@ docker run -d \ voucher/vouch-proxy ``` -The [voucher/vouch-proxy](https://hub.docker.com/r/voucher/vouch-proxy/) Docker image is an automated build on Docker Hub. In addition to `voucher/vouch-proxy:latest` (based on [scratch](https://docs.docker.com/samples/library/scratch/)) there are versioned images as `voucher/vouch-proxy:x.y.z` and an [alpine](https://docs.docker.com/samples/library/alpine/) based `voucher/vouch-proxy:alpine` for the current version. +or + +```bash +docker run -d \ + -p 9090:9090 \ + --name vouch-proxy \ + -e VOUCH_DOMAINS=yourdomain.com + -e OAUTH_PROVIDER=google + -e OAUTH_CLIENT_ID=1234 + -e OAUTH_CLIENT_SECRET=secretsecret + -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth + voucher/vouch-proxy +``` + +Automated container builds for each Vouch Proxy release are available from [Docker Hub](https://hub.docker.com/r/voucher/vouch-proxy/). Each release produces.. -[https://hub.docker.com/r/voucher/vouch-proxy/builds/](https://hub.docker.com/r/voucher/vouch-proxy/builds/) +- `voucher/vouch-proxy:latest` +- `voucher/vouch-proxy:x.y.z` +- `voucher/vouch-proxy:alpine` +- `voucher/vouch-proxy:latest-arm` ## Kubernetes Nginx Ingress diff --git a/config/config.yml_example b/config/config.yml_example index 42995f8c..22cb965a 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -5,18 +5,22 @@ # be aware of the yaml indentation, the only top level elements are `vouch` and `oauth`. +# Vouch Proxy can also be configured using Environmental Variables. The associated env var for +# each configuration is shown such as VOUCH_LOGLEVEL. + vouch: - # logLevel: debug + # logLevel: debug # VOUCH_LOGLEVEL logLevel: info - # testing - force all 302 redirects to be rendered as a webpage with a link + # testing: false - VOUCH_TESTING + # force all 302 redirects to be rendered as a webpage with a link # if you're having problems, turn on testing testing: true - listen: 0.0.0.0 - port: 9090 + listen: 0.0.0.0 # VOUCH_LISTEN + port: 9090 # VOUCH_PORT - # domains - + # domains - VOUCH_DOMAINS # each of these domains must serve the url https://vouch.$domains[0] https://vouch.$domains[1] ... # so that the cookie which stores the JWT can be set in the relevant domain # you usually *don't* want to list every individual website that will be protected @@ -28,21 +32,22 @@ vouch: - yourdomain.com - yourotherdomain.com - # Set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # Set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider - VOUCH_ALLOWALLUSERS # allowAllUsers: false - # Setting publicAccess: true will accept all requests, even without a cookie. + # Setting publicAccess: true will accept all requests, even without a cookie. - VOUCH_PUBLICACCESS # If the user is logged in, the cookie will be validated and the user header will be set. # You will need to direct people to the Vouch Proxy login page from your application. # publicAccess: false - # whiteList - (optional) allows only the listed usernames + # whiteList (optional) allows only the listed usernames - VOUCH_WHITELIST # usernames are usually email addresses (google, most oidc providers) or login/username for github and github enterprise whiteList: - bob@yourdomain.com - alice@yourdomain.com - joe@yourdomain.com + # teamWhitelist - VOUCH_TEAMWHITELIST # only used for github orgs/teams # teamWhitelist: # - vouch @@ -50,7 +55,8 @@ vouch: # - myOrg/myTeam jwt: - # secret - a random string used to cryptographically sign the jwt + # secret - VOUCH_JWT_SECRET + # a random string used to cryptographically sign the jwt # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes) # if the secret is not set here then Vouch Proxy will.. # - look for the secret in `./config/secret` @@ -59,39 +65,39 @@ vouch: # you'll want them all to have the same secret secret: your_random_string - issuer: Vouch + # issuer: Vouch # VOUCH_JWT_ISSUER - # number of minutes until jwt expires + # number of minutes until jwt expires - VOUCH_JWT_MAXAGE maxAge: 240 - # compress the jwt - compress: true + # compress the jwt - VOUCH_JWT_COMPRESS + compress: true cookie: - # name of cookie to store the jwt + # name of cookie to store the jwt - VOUCH_COOKIE_NAME name: VouchCookie # optionally force the domain of the cookie to set - # domain: yourdomain.com + # domain: yourdomain.com # VOUCH_COOKIE_DOMAIN - # Set `secure: false` when protecting a non-https site such as http://app.yourdmain.com + # Set `secure: false` when protecting a non-https site such as http://app.yourdmain.com - VOUCH_COOKIE_SECURE secure: true - httpOnly: true + # httpOnly: true # VOUCH_COOKIE_HTTPONLY - # Set cookie maxAge to 0 to delete the cookie every time the browser is closed. + # Set cookie maxAge to 0 to delete the cookie every time the browser is closed. - VOUCH_COOKIE_MAXAGE maxAge: 14400 - # Set SameSite attribute to restrict browser behaviour wrt sending the cookie along with cross-site requests. + # Set SameSite attribute to restrict browser behaviour wrt sending the cookie along with cross-site requests. - VOUCH_COOKIE_SAMESITE # Possible attribute values lax, strict, none. # If attribute not specified then cross-site behaviour will depend on the browser used. If sameSite=none then secure must be set to true # More context: https://github.com/vouch/vouch-proxy/issues/210 sameSite: lax session: - # name of session variable stored locally + # name of session variable stored locally - VOUCH_SESSION_NAME name: VouchSession - # key - a cryptographic string used to store the session variable + # key - a cryptographic string used to store the session variable - VOUCH_SESSION_KEY # if the key is not set here then it is generated at startup and stored in memory # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes) # you only want to set this if you're running multiple user facing vouch.yourdomain.com instances @@ -100,9 +106,9 @@ vouch: headers: - jwt: X-Vouch-Token - querystring: access_token - redirect: X-Vouch-Requested-URI + jwt: X-Vouch-Token # VOUCH_HEADERS_JWT + querystring: access_token # VOUCH_HEADERS_QUERYSTRING + redirect: X-Vouch-Requested-URI # VOUCH_HEADERS_REDIRECT # GENERAL WARNING ABOUT claims AND tokens # all of these config elements can cause performance impacts due to the amount of information being @@ -112,7 +118,7 @@ vouch: # see `large_client_header_buffers` http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers # and `proxy_buffer_size` http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size - # claims - a list of claims that will be stored in the JWT and passed down to applications via headers + # claims - a list of claims that will be stored in the JWT and passed down to applications via headers - VOUCH_HEADERS_CLAIMS # By default claims are sent down as headers with a prefix of X-Vouch-IdP-Claims-ClaimKey # Only when a claim is found in the user's info will the header exist. This is optional. These are case sensitive. claims: @@ -126,19 +132,20 @@ vouch: # $auth_resp_x_vouch_idp_claims_given-name # see https://github.com/vouch/vouch-proxy/issues/183 regarding claims and header naming - # claimheader - Customizable claim header prefix (instead of default `X-Vouch-IdP-Claims-`) + # claimheader - Customizable claim header prefix (instead of default `X-Vouch-IdP-Claims-`) - VOUCH_HEADERS_CLAIMHEADER # claimheader: My-Custom-Claim-Prefix - # accesstoken - Pass the user's access token from the provider. This is useful if you need to pass the IdP token to a downstream + # accesstoken - Pass the user's access token from the provider. This is useful if you need to pass the IdP token to a downstream - VOUCH_HEADERS_ACCESSTOKEN # application. This is optional. # accesstoken: X-Vouch-IdP-AccessToken - # idtoken - Pass the user's Id token from the provider. This is useful if you need to pass this token to a downstream + # idtoken - Pass the user's Id token from the provider. This is useful if you need to pass this token to a downstream - VOUCH_HEADERS_IDTOKEN # application. This is optional. # idtoken: X-Vouch-IdP-IdToken - # test_url - add this URL to the page which vouch displays during testing (a convenience for testing) + # test_url - add this URL to the page which vouch displays during testing (a convenience for testing) - VOUCH_TESTURL test_url: http://yourdomain.com + # post_logout_redirect_uris - VOUCH_POST_LOGOUT_REDIRECT_URIS # in order to prevent redirection attacks all redirected URLs to /logout must be specified # the URL must still be passed to Vouch Proxy as https://vouch.yourdomain.com/logout?url=${ONE OF THE URLS BELOW} # in line with the OIDC spec https://openid.net/specs/openid-connect-session-1_0.html#RedirectionAfterLogout @@ -151,10 +158,30 @@ vouch: # you may be daisy chaining to your IdP - https://myorg.okta.com/oauth2/123serverid/v1/logout?post_logout_redirect_uri=http://myapp.yourdomain.com/login + +# +# OAuth +# + +# environmental variables for OAuth config: +# provider: OAUTH_PROVIDER +# client_id: OAUTH_CLIENT_ID +# client_secret: OAUTH_CLIENT_SECRET +# auth_url: OAUTH_AUTH_URL +# token_url: OAUTH_TOKEN_URL +# end_session_endpoint: OAUTH_END_SESSION_ENDPOINT +# callback_url: OAUTH_CALLBACK_URL +# user_info_url: OAUTH_USER_INFO_URL +# user_team_url: OAUTH_USER_TEAM_URL +# user_org_url: OAUTH_USER_ORG_URL +# preferreddomain: OAUTH_PREFERREDDOMAIN +# callback_urls: OAUTH_CALLBACK_URLS +# scopes: OAUTH_SCOPES + # -# OAuth Provider # configure ONLY ONE of the following oauth providers # + oauth: # Google @@ -208,4 +235,5 @@ oauth: client_id: http://yourdomain.com auth_url: https://indielogin.com/auth callback_url: http://vouch.yourdomain.com:9090/auth - + + From 6b0b958fb496bbb663f7884dfe488e56ba2b340e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 13:59:32 -0700 Subject: [PATCH 417/736] #132 no zero values in defaults --- config/.defaults.yml | 52 +++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/config/.defaults.yml b/config/.defaults.yml index 8238c4e0..54e2f3bb 100644 --- a/config/.defaults.yml +++ b/config/.defaults.yml @@ -9,30 +9,29 @@ vouch: testing: false listen: 0.0.0.0 port: 9090 - domains: - - + # domains: allowAllUsers: false publicAccess: false - whiteList: - teamWhitelist: + # whiteList: + # teamWhitelist: jwt: - secret: + # secret: issuer: Vouch maxAge: 240 compress: true cookie: name: VouchCookie - domain: + # domain: secure: true httpOnly: true maxAge: 240 - sameSite: + # sameSite: session: name: VouchSession - key: + # key: headers: jwt: X-Vouch-Token @@ -41,28 +40,21 @@ vouch: error: X-Vouch-Error querystring: access_token redirect: X-Vouch-Requested-URI - claims: - - + # claims: claimheader: X-Vouch-IdP-Claims- accesstoken: X-Vouch-IdP-AccessToken idtoken: X-Vouch-IdP-IdToken - test_url: - post_logout_redirect_uris: - - - -oauth: - provider: - # create new credentials at: - # https://console.developers.google.com/apis/credentials - client_id: - client_secret: - callback_url: - callback_urls: - - - preferredDomain: yourdomain.com - auth_url: - token_url: - user_info_url: - end_session_endpoint: - scopes: - - + # test_url: + # post_logout_redirect_uris: +# oauth: +# provider: +# client_id: +# client_secret: +# callback_url: +# callback_urls: +# preferredDomain: +# auth_url: +# token_url: +# user_info_url: +# end_session_endpoint: +# scopes: From 3fd1a7cf689b74e80f551d20ba601468025a3f76 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 14:01:41 -0700 Subject: [PATCH 418/736] #132 validate Cfg object, not viper.isSet --- .gitignore | 3 ++- main.go | 6 +++-- pkg/cfg/cfg.go | 62 +++++++++++++++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 48af7045..5ba43587 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ config/secret pkg/model/storage-test.db .vscode/* coverage.out -coverage.html \ No newline at end of file +coverage.html.env_google +.env* diff --git a/main.go b/main.go index 742706bf..043f3c0c 100644 --- a/main.go +++ b/main.go @@ -93,11 +93,13 @@ func configure() { cfg.Configure() healthcheck.CheckAndExitIfIsHealthCheck() - cfg.ValidateConfiguration() - logger = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger + if err := cfg.ValidateConfiguration(); err != nil { + logger.Fatal(err) + } + domains.Configure() jwtmanager.Configure() cookie.Configure() diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 3986f10a..75c04de7 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -17,6 +17,7 @@ import ( "net/http" "os" "path/filepath" + "reflect" "strings" "github.com/kelseyhightower/envconfig" @@ -92,9 +93,6 @@ var ( // Branding that's our name Branding = branding{"vouch", "VOUCH", "Vouch", "Vouch Proxy", "https://github.com/vouch/vouch-proxy"} - // RequiredOptions must have these fields set for minimum viable config - RequiredOptions = []string{"oauth.provider", "oauth.client_id"} - // RootDir is where Vouch Proxy looks for ./config/config.yml, ./data, ./static and ./templates RootDir string @@ -114,6 +112,9 @@ var ( Cfg = &Config{} // IsHealthCheck see main.go IsHealthCheck = false + + errConfigNotFound = errors.New("configuration file not found") + errConfigIsBad = errors.New("configuration file not found") ) type cmdLineFlags struct { @@ -155,9 +156,14 @@ func Configure() { } setDefaults() - parseConfigFile() - // configureFromEnvVars() - configureFromEnv() + configFileErr := parseConfigFile() + + didConfigFromEnv := configureFromEnv() + + if !didConfigFromEnv && configFileErr != nil { + // then it's probably config file not found + log.Fatal(configFileErr) + } fixConfigOptions() Logging.configure() @@ -173,31 +179,36 @@ func Configure() { // using envconfig // https://github.com/kelseyhightower/envconfig -func configureFromEnv() { +func configureFromEnv() bool { + preEnvConfig := *Cfg err := envconfig.Process(Branding.UCName, Cfg) if err != nil { log.Fatal(err.Error()) } + preEnvGenOAuth := *GenOAuth err = envconfig.Process("OAUTH", GenOAuth) if err != nil { log.Fatal(err.Error()) } - + // did anything change? + if !reflect.DeepEqual(preEnvConfig, *Cfg) || + !reflect.DeepEqual(preEnvGenOAuth, *GenOAuth) { + log.Debugf("preEnvConfig %+v", preEnvConfig) + log.Debugf("Cfg %+v", Cfg) + log.Infof("%s configuration set from Environmental Variables", Branding.FullName) + return true + } + return false } // ValidateConfiguration confirm the Configuration is valid -func ValidateConfiguration() { +func ValidateConfiguration() error { if Cfg.Testing { // Logging.setLogLevel(zap.DebugLevel) Logging.setDevelopmentLogger() } - errT := basicTest() - if errT != nil { - log.Panic(errT) - } - - log.Debugf("viper settings %+v", viper.AllSettings()) + return basicTest() } func setRootDir() { @@ -216,7 +227,7 @@ func setRootDir() { } // parseConfig parse the config file -func parseConfigFile() { +func parseConfigFile() error { configEnv := os.Getenv(Branding.UCName + "_CONFIG") if configEnv != "" { @@ -236,8 +247,7 @@ func parseConfigFile() { } err := viper.ReadInConfig() // Find and read the config file if err != nil { // Handle errors reading the config file - log.Fatalf("Fatal error config file: %s", err.Error()) - log.Panic(err) + return fmt.Errorf("%w: %s", errConfigNotFound, err) } if err = checkConfigFileWellFormed(); err != nil { @@ -250,8 +260,11 @@ func parseConfigFile() { log.Error(err) } + log.Debugf("viper settings %+v", viper.AllSettings()) + // don't log the secret! // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) + return nil } func fixConfigOptions() { @@ -321,13 +334,16 @@ func basicTest() error { return err } - for _, opt := range RequiredOptions { - if !viper.IsSet(opt) { - return errors.New("configuration error: required configuration option " + opt + " is not set") - } + if GenOAuth.Provider == "" { + return errors.New("configuration error: required configuration option 'oauth.provider' is not set") } + if GenOAuth.ClientID == "" { + return errors.New("configuration error: required configuration option 'oauth.client_id' is not set") + } + // Domains is required _unless_ Cfg.AllowAllUsers is set - if !viper.IsSet(Branding.LCName+".allowAllUsers") && !viper.IsSet(Branding.LCName+".domains") { + if (!Cfg.AllowAllUsers && len(Cfg.Domains) == 0) || + (Cfg.AllowAllUsers && len(Cfg.Domains) > 0) { return fmt.Errorf("configuration error: either one of %s or %s needs to be set (but not both)", Branding.LCName+".domains", Branding.LCName+".allowAllUsers") } From a9e0f6196506bb08aeb633ca6a59fec766e8e155 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 14:03:01 -0700 Subject: [PATCH 419/736] clarify error for cookie.secure != http --- handlers/login.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/login.go b/handlers/login.go index d59cfaa7..2d599e5e 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -155,7 +155,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { // if the requested URL is http then the cookie cannot be seen if cfg.Cfg.Cookie.Secure is set if u.Scheme == "http" && cfg.Cfg.Cookie.Secure { - return "", fmt.Errorf("%w: mismatch between requested destination URL and %s.cookie.secure %v (the cookie will not be visible to https)", errInvalidURL, cfg.Branding.LCName, cfg.Cfg.Cookie.Secure) + return "", fmt.Errorf("%w: mismatch between requested destination URL and '%s.cookie.secure: %v' (the cookie is only visible to 'https' but the requested site is 'http')", errInvalidURL, cfg.Branding.LCName, cfg.Cfg.Cookie.Secure) } return urlparam, nil From 9f0f1719c17030482a981dcc30caee6b515a2708 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 14:44:47 -0700 Subject: [PATCH 420/736] #132 TestConfigEnvPrecedence --- pkg/cfg/cfg_test.go | 32 ++++++++++++++++++++++++++++---- pkg/cfg/oauth_test.go | 7 ------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index f8e69aed..46676604 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -13,12 +13,18 @@ package cfg import ( "fmt" "os" + "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" ) +func setUp(configFile string) { + os.Setenv("VOUCH_CONFIG", filepath.Join(os.Getenv("VOUCH_ROOT"), configFile)) + InitForTestPurposes() +} + func TestConfigParsing(t *testing.T) { InitForTestPurposes() Configure() @@ -31,6 +37,21 @@ func TestConfigParsing(t *testing.T) { assert.NotEmpty(t, Cfg.JWT.MaxAge) +} +func TestConfigEnvPrecedence(t *testing.T) { + t.Cleanup(cleanupEnv) + + envVar := "OAUTH_CLIENT_SECRET" + envVal := "testing123" + + os.Setenv(envVar, envVal) + // Configure() + setUp("/config/testing/handler_login_url.yml") + + assert.Equal(t, envVal, GenOAuth.ClientSecret) + + // assert.NotEmpty(t, Cfg.JWT.MaxAge) + } func TestSetGitHubDefaults(t *testing.T) { @@ -75,7 +96,7 @@ func Test_claimToHeader(t *testing.T) { } func Test_configureFromEnvCfg(t *testing.T) { - + t.Cleanup(cleanupEnv) // each of these env vars holds a.. // string // get all the values @@ -149,12 +170,10 @@ func Test_configureFromEnvCfg(t *testing.T) { }) } - os.Clearenv() - os.Setenv(Branding.UCName+"_ROOT", RootDir) - } func Test_configureFromEnvOAuth(t *testing.T) { + t.Cleanup(cleanupEnv) // each of these env vars holds a.. // string @@ -215,7 +234,12 @@ func Test_configureFromEnvOAuth(t *testing.T) { } }) } +} + +func cleanupEnv() { os.Clearenv() os.Setenv(Branding.UCName+"_ROOT", RootDir) + Cfg = &Config{} + GenOAuth = &oauthConfig{} } diff --git a/pkg/cfg/oauth_test.go b/pkg/cfg/oauth_test.go index f86b07ec..8a5d038b 100644 --- a/pkg/cfg/oauth_test.go +++ b/pkg/cfg/oauth_test.go @@ -11,16 +11,9 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( - "os" - "path/filepath" "testing" ) -func setUp(configFile string) { - os.Setenv("VOUCH_CONFIG", filepath.Join(os.Getenv("VOUCH_ROOT"), configFile)) - InitForTestPurposes() -} - func Test_checkCallbackConfig(t *testing.T) { setUp("/config/testing/handler_login_url.yml") From 70d5170314bc88943f31a96d4f4f3894a4992356 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 14:45:14 -0700 Subject: [PATCH 421/736] #132 VOUCH_CONFIG usage --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 512ecf2d..599a7a36 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,8 @@ Environmental variable names are documented in [config/config.yml_example](https All lists with multiple values must be comma separated: `VOUCH_DOMAINS="yourdomain.com,yourotherdomain.com"` +The variable `VOUCH_CONFIG` can be used to set an alternate location for the configuration file. `VOUCH_ROOT` can be used to set an alternate root directory for Vouch Proxy to look for support files. + ## More advanced configurations - [cacheing of the Vouch Proxy validation response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) From 34ba59a3342a88eb75906e46c952a988470b835f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 17:20:17 -0700 Subject: [PATCH 422/736] Merge branch 'fix/bad_file' From cb0a0f19e6de7d5b23df5cc7a33114128d92ed91 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 18:50:34 -0700 Subject: [PATCH 423/736] #132 mv .defaults to RootDir in support of docker The documented and common practice is to `docker run` with the mapped volume `-v ./config:./config`. This has the side effect of overwriting the `/.defaults.yml` file. --- config/.defaults.yml => .defaults.yml | 0 Dockerfile | 1 + Dockerfile.alpine | 1 + pkg/cfg/cfg.go | 4 ++-- 4 files changed, 4 insertions(+), 2 deletions(-) rename config/.defaults.yml => .defaults.yml (100%) diff --git a/config/.defaults.yml b/.defaults.yml similarity index 100% rename from config/.defaults.yml rename to .defaults.yml diff --git a/Dockerfile b/Dockerfile index 3ad05ac5..744ab2e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,7 @@ FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY templates/ templates/ +COPY .defaults.yml .defaults.yml # see note for /static in main.go COPY static /static COPY --from=builder /go/bin/vouch-proxy /vouch-proxy diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 1d120cd6..769d29cb 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -21,6 +21,7 @@ FROM alpine:latest LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY templates/ templates/ +COPY .defaults.yml .defaults.yml # see note for /static in main.go COPY static /static COPY do.sh /do.sh diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 75c04de7..a4bd1891 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -375,12 +375,12 @@ func basicTest() error { return nil } -// setDefaults set default options for most items +// setDefaults set default options for most items from `.defaults.yml` in the root dir func setDefaults() { viper.SetConfigName(".defaults") viper.SetConfigType("yaml") - viper.AddConfigPath(filepath.Join(RootDir, "config")) + viper.AddConfigPath(RootDir) viper.ReadInConfig() if err := viper.UnmarshalKey(Branding.LCName, &Cfg); err != nil { log.Error(err) From 3ee8aed86dda4d8f0ecc628893fbae6fcae69695 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 19:14:33 -0700 Subject: [PATCH 424/736] complete mv of .defaults.yml --- config/.defaults.yml | 60 -------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 config/.defaults.yml diff --git a/config/.defaults.yml b/config/.defaults.yml deleted file mode 100644 index 54e2f3bb..00000000 --- a/config/.defaults.yml +++ /dev/null @@ -1,60 +0,0 @@ -# default values for Vouch Proxy -# this is related to Env Vars -# https://github.com/vouch/vouch-proxy/issues/132 -# https://github.com/vouch/vouch-proxy/pull/134 - -# you don't want to mess with these -vouch: - logLevel: info - testing: false - listen: 0.0.0.0 - port: 9090 - # domains: - allowAllUsers: false - publicAccess: false - # whiteList: - # teamWhitelist: - - jwt: - # secret: - issuer: Vouch - maxAge: 240 - compress: true - - cookie: - name: VouchCookie - # domain: - secure: true - httpOnly: true - maxAge: 240 - # sameSite: - - session: - name: VouchSession - # key: - - headers: - jwt: X-Vouch-Token - user: X-Vouch-User - success: X-Vouch-Success - error: X-Vouch-Error - querystring: access_token - redirect: X-Vouch-Requested-URI - # claims: - claimheader: X-Vouch-IdP-Claims- - accesstoken: X-Vouch-IdP-AccessToken - idtoken: X-Vouch-IdP-IdToken - # test_url: - # post_logout_redirect_uris: -# oauth: -# provider: -# client_id: -# client_secret: -# callback_url: -# callback_urls: -# preferredDomain: -# auth_url: -# token_url: -# user_info_url: -# end_session_endpoint: -# scopes: From 14274b2730f2d9bc04d3fef721ed403658509b7e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 19:17:08 -0700 Subject: [PATCH 425/736] Merge branch 'feature/132_env_vars' From c5a9188a50525b38263f1d6df68730d90d905f4e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 21 May 2020 19:30:46 -0700 Subject: [PATCH 426/736] upgrade to go 1.14 1.14 includes testing.Cleanup() which is used in the env var testing --- .travis.yml | 2 +- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ffebb5b0..a638b8fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.13" + - "1.14" env: - ISTRAVIS=true diff --git a/Dockerfile b/Dockerfile index 744ab2e2..b2e346ca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.13 AS builder +FROM golang:1.14 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 769d29cb..0bf757b7 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.13 AS builder +FROM golang:1.14 AS builder LABEL maintainer="vouch@bnf.net" From 00e965cfb1cc69470cc9aed328189d149afdae4e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 22 May 2020 05:02:21 -0700 Subject: [PATCH 427/736] update job name to 'notify-irc' --- .github/workflows/notify-irc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/notify-irc.yml b/.github/workflows/notify-irc.yml index d4c4a72e..3cbf0b0a 100644 --- a/.github/workflows/notify-irc.yml +++ b/.github/workflows/notify-irc.yml @@ -2,7 +2,7 @@ name: "Push Notification" on: [push, pull_request, create] jobs: - test: + notify-irc: runs-on: ubuntu-latest steps: - name: irc push From 2448fa99cb75f8d620dd6ddb41248dde9d84ed4b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 22 May 2020 05:24:58 -0700 Subject: [PATCH 428/736] #270 set session timeout to five minutes --- handlers/auth.go | 1 + handlers/handlers.go | 12 ++++++------ handlers/logout.go | 3 +-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index 62f91eec..72668828 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -88,6 +88,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { // clear out the session value session.Values["requestedURL"] = "" session.Values[requestedURL] = 0 + session.Options.MaxAge = -1 if err = session.Save(r, w); err != nil { log.Error(err) } diff --git a/handlers/handlers.go b/handlers/handlers.go index c690377c..7831effb 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -13,6 +13,11 @@ package handlers import ( "net/http" + "github.com/gorilla/sessions" + "go.uber.org/zap" + + "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/providers/adfs" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/providers/github" @@ -22,12 +27,6 @@ import ( "github.com/vouch/vouch-proxy/pkg/providers/nextcloud" "github.com/vouch/vouch-proxy/pkg/providers/openid" "github.com/vouch/vouch-proxy/pkg/providers/openstax" - - "go.uber.org/zap" - - "github.com/gorilla/sessions" - "github.com/vouch/vouch-proxy/pkg/cfg" - "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/structs" ) @@ -57,6 +56,7 @@ func Configure() { sessstore.Options.HttpOnly = cfg.Cfg.Cookie.HTTPOnly sessstore.Options.Secure = cfg.Cfg.Cookie.Secure sessstore.Options.SameSite = cookie.SameSite() + sessstore.Options.MaxAge = 300 // give the user five minutes to log in at the IdP provider = getProvider() provider.Configure() diff --git a/handlers/logout.go b/handlers/logout.go index 55b8fc8e..46a920dc 100644 --- a/handlers/logout.go +++ b/handlers/logout.go @@ -43,15 +43,14 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) { cookie.ClearCookie(w, r) log.Debug("/logout deleting session") - sessstore.MaxAge(-1) session, err := sessstore.Get(r, cfg.Cfg.Session.Name) + session.Options.MaxAge = -1 if err != nil { log.Error(err) } if err = session.Save(r, w); err != nil { log.Error(err) } - sessstore.MaxAge(300) providerLogoutURL := cfg.GenOAuth.LogoutURL redirectURL := r.URL.Query().Get("url") From bd8c2be0ccbe5c5f32a0d39af8e44461ba0b965b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 22 May 2020 10:06:00 -0700 Subject: [PATCH 429/736] add docker alpine build and run --- do.sh | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/do.sh b/do.sh index 8047bf44..3271c6a6 100755 --- a/do.sh +++ b/do.sh @@ -9,7 +9,8 @@ cd $SDIR export VOUCH_ROOT=${GOPATH}/src/github.com/vouch/vouch-proxy/ -IMAGE=voucher/vouch-proxy +IMAGE=voucher/vouch-proxy:latest +ALPINE=voucher/vouch-proxy:alpine GOIMAGE=golang:1.14 NAME=vouch-proxy HTTPPORT=9090 @@ -40,6 +41,10 @@ dbuild () { docker build -f Dockerfile -t $IMAGE . } +dbuildalpine () { + docker build -f Dockerfile.alpine -t $ALPINE . +} + gobuildstatic () { export CGO_ENABLED=0 export GOOS=linux @@ -47,12 +52,12 @@ gobuildstatic () { } drun () { - if [ "$(docker ps | grep $NAME)" ]; then - docker stop $NAME - docker rm $NAME - fi + if [ "$(docker ps | grep $NAME)" ]; then + docker stop $NAME + docker rm $NAME + fi - CMD="docker run --rm -i -t + CMD="docker run --rm -i -t -p ${HTTPPORT}:${HTTPPORT} --name $NAME -v ${SDIR}/config:/config @@ -62,6 +67,11 @@ drun () { $CMD } +drunalpine () { + IMAGE=$ALPINE + drun $* +} + watch () { CMD=$@; @@ -313,6 +323,8 @@ usage() { $0 gofmt - gofmt the entire code base $0 dbuild - build docker container $0 drun [args] - run docker container + $0 dbuildalpine - build docker container for alpine + $0 drunalpine [args] - run docker container for alpine $0 test [./pkg_test.go] - run go tests (defaults to all tests) $0 test_logging - test the logging output $0 coverage - coverage report @@ -333,7 +345,26 @@ EOF ARG=$1; case "$ARG" in - 'run'|'build'|'dbuild'|'drun'|'install'|'test'|'goget'|'gogo'|'watch'|'gobuildstatic'|'coverage'|'stats'|'usage'|'bug_report'|'test_logging'|'license'|'profile'|'gofmt') + 'run' \ + |'build' \ + |'dbuild' \ + |'drun' \ + |'dbuildalpine' \ + |'drunalpine' \ + |'install' \ + |'test' \ + |'goget' \ + |'gogo' \ + |'watch' \ + |'gobuildstatic' \ + |'coverage' \ + |'stats' \ + |'usage' \ + |'bug_report' \ + |'test_logging' \ + |'license' \ + |'profile' \ + |'gofmt') shift $ARG $* ;; From ab753455d1b1113b6dfa8d1517746408ca0e9164 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 22 May 2020 19:28:01 -0700 Subject: [PATCH 430/736] add docker image voucher/vouch-proxy:alpine-x.y.z --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 599a7a36..b6c13a6d 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,7 @@ Automated container builds for each Vouch Proxy release are available from [Dock - `voucher/vouch-proxy:latest` - `voucher/vouch-proxy:x.y.z` - `voucher/vouch-proxy:alpine` +- `voucher/vouch-proxy:alpine-x.y.z` - `voucher/vouch-proxy:latest-arm` ## Kubernetes Nginx Ingress From 6006bad04b42b2e3db57dc2cbfe7768ce60f75cc Mon Sep 17 00:00:00 2001 From: Jim Lamb Date: Fri, 29 May 2020 07:44:37 +0100 Subject: [PATCH 431/736] Issue 274 - log copy of Cfg with masked secrets --- pkg/cfg/cfg.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index a4bd1891..16573b13 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -194,7 +194,15 @@ func configureFromEnv() bool { if !reflect.DeepEqual(preEnvConfig, *Cfg) || !reflect.DeepEqual(preEnvGenOAuth, *GenOAuth) { log.Debugf("preEnvConfig %+v", preEnvConfig) - log.Debugf("Cfg %+v", Cfg) + // Mask sensitive configuration items before logging + maskedCfg := *Cfg + if len(Cfg.Session.Key) != 0 { + maskedCfg.Session.Key = "XXXXXXXX" + } + if len(Cfg.JWT.Secret) != 0 { + maskedCfg.JWT.Secret = "XXXXXXXX" + } + log.Debugf("Cfg %+v", maskedCfg) log.Infof("%s configuration set from Environmental Variables", Branding.FullName) return true } From 1a56162e75dd7c38d519866efb0039f003e5ac4d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 29 May 2020 10:03:20 -0700 Subject: [PATCH 432/736] only warn if domains configured --- pkg/domains/domains.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/domains/domains.go b/pkg/domains/domains.go index 0aaf07ad..32fbfbd4 100644 --- a/pkg/domains/domains.go +++ b/pkg/domains/domains.go @@ -27,8 +27,6 @@ func Configure() { } // Matches returns one of the domains we're configured for -// TODO return all matches -// Matches return the first match of the func Matches(s string) string { if strings.Contains(s, ":") { // then we have a port and we just want to check the host @@ -37,13 +35,15 @@ func Matches(s string) string { s = split[0] } - for i, v := range cfg.Cfg.Domains { - if s == v || strings.HasSuffix(s, "."+v) { - log.Debugf("domain %s matched array value at [%d]=%v", s, i, v) - return v + if len(cfg.Cfg.Domains) > 0 { + for i, v := range cfg.Cfg.Domains { + if s == v || strings.HasSuffix(s, "."+v) { + log.Debugf("domain %s matched array value at [%d]=%v", s, i, v) + return v + } } + log.Warnf("domain %s not found in any domains %v", s, cfg.Cfg.Domains) } - log.Warnf("domain %s not found in any domains %v", s, cfg.Cfg.Domains) return "" } From 3885754e04d14cf5c154535a1b39b3e5f4984068 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 29 May 2020 10:17:58 -0700 Subject: [PATCH 433/736] log failure to find callback if > 1 callback_url --- handlers/login.go | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 2d599e5e..cc752d6d 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -86,9 +86,9 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // SUCCESS // bounce to oauth provider for login - var lURL = loginURL(r, state) - log.Debugf("redirecting to oauthURL %s", lURL) - responses.Redirect302(w, r, lURL) + var oURL = oauthLoginURL(r, state) + log.Debugf("redirecting to oauthURL %s", oURL) + responses.Redirect302(w, r, oURL) } var ( @@ -161,7 +161,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { return urlparam, nil } -func loginURL(r *http.Request, state string) string { +func oauthLoginURL(r *http.Request, state string) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var lurl string @@ -171,15 +171,25 @@ func loginURL(r *http.Request, state string) string { } else if cfg.GenOAuth.Provider == cfg.Providers.ADFS { lurl = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) } else { - domain := domains.Matches(r.Host) - log.Debugf("/login looking for callback_url matching %v", domain) - for i, v := range cfg.GenOAuth.RedirectURLs { - if strings.Contains(v, domain) { - log.Debugf("/login redirect value matched at [%d]=%v", i, v) - cfg.OAuthClient.RedirectURL = v - break + // cfg.OAuthClient.RedirectURL is set in cfg + // this checks the multiple redirect case for mulitple matching domains + if len(cfg.GenOAuth.RedirectURLs) > 0 { + found := false + domain := domains.Matches(r.Host) + log.Debugf("/login looking for callback_url matching %s", domain) + for _, v := range cfg.GenOAuth.RedirectURLs { + if strings.Contains(v, domain) { + found = true + log.Debugf("/login callback_url set to %s", v) + cfg.OAuthClient.RedirectURL = v + break + } + } + if !found { + log.Infof("/login no callback_url matched %s (is the `Host` header being passed to Vouch Proxy?)", domain) } } + // Google and a few other IdPs allow other options to be set if cfg.OAuthopts != nil { lurl = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) } else { From 74451b209fe593bdb1e56a3e3403892b74f6a0b3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 29 May 2020 11:19:10 -0700 Subject: [PATCH 434/736] #274 set LogLevel from env before log.Debug() call --- pkg/cfg/cfg.go | 5 +++++ pkg/cfg/cfg_test.go | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 16573b13..2f756500 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -193,6 +193,11 @@ func configureFromEnv() bool { // did anything change? if !reflect.DeepEqual(preEnvConfig, *Cfg) || !reflect.DeepEqual(preEnvGenOAuth, *GenOAuth) { + + // set logLevel before calling Log.Debugf() + if preEnvConfig.LogLevel != Cfg.LogLevel { + Logging.setLogLevelString(Cfg.LogLevel) + } log.Debugf("preEnvConfig %+v", preEnvConfig) // Mask sensitive configuration items before logging maskedCfg := *Cfg diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 46676604..371d4ca1 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -100,7 +100,7 @@ func Test_configureFromEnvCfg(t *testing.T) { // each of these env vars holds a.. // string // get all the values - senv := []string{"VOUCH_LOGLEVEL", "VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", + senv := []string{"VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY"} @@ -117,7 +117,11 @@ func Test_configureFromEnvCfg(t *testing.T) { for _, v := range senv { os.Setenv(v, svalue) } + // "VOUCH_LOGLEVEL" is special since logging is occuring during these tests, needs to be an actual level + os.Setenv("VOUCH_LOGLEVEL", "debug") + savalue := []string{"arrayone", "arraytwo", "arraythree"} + for _, v := range saenv { os.Setenv(v, strings.Join(savalue, ",")) t.Logf("savalue: %s", savalue) @@ -133,7 +137,7 @@ func Test_configureFromEnvCfg(t *testing.T) { // run the thing configureFromEnv() - scfg := []string{Cfg.LogLevel, Cfg.Listen, Cfg.JWT.Issuer, Cfg.JWT.Secret, Cfg.Headers.JWT, + scfg := []string{Cfg.Listen, Cfg.JWT.Issuer, Cfg.JWT.Secret, Cfg.Headers.JWT, Cfg.Headers.User, Cfg.Headers.QueryString, Cfg.Headers.Redirect, Cfg.Headers.Success, Cfg.Headers.Error, Cfg.Headers.ClaimHeader, Cfg.Headers.AccessToken, Cfg.Headers.IDToken, Cfg.Cookie.Name, Cfg.Cookie.Domain, Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, @@ -155,6 +159,7 @@ func Test_configureFromEnvCfg(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, Cfg.LogLevel, "debug", "Cfg.LogLevel is not debug") for i, v := range scfg { assert.Equal(t, svalue, v, fmt.Sprintf("%d: v is %s not %s", i, v, svalue)) } From bd7a8cfec1214e0c0c72dae2ff4b9cb1e788c8cf Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 29 May 2020 11:19:35 -0700 Subject: [PATCH 435/736] #274 move debug logging of config post LogLevel --- pkg/cfg/cfg.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 2f756500..68a0d4b6 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -175,6 +175,7 @@ func Configure() { Cfg.Port = *CmdLine.port } + logConfigIfDebug() } // using envconfig @@ -235,7 +236,6 @@ func setRootDir() { log.Panic(errEx) } RootDir = filepath.Dir(ex) - log.Debugf("cfg.RootDir: %s", RootDir) } } @@ -272,14 +272,17 @@ func parseConfigFile() error { if err = UnmarshalKey(Branding.LCName, &Cfg); err != nil { log.Error(err) } - - log.Debugf("viper settings %+v", viper.AllSettings()) - // don't log the secret! // log.Debugf("secret: %s", string(Cfg.JWT.Secret)) return nil } +// consolidate config related Log.Debugf() calls so that they can be placed *after* we set the logLevel +func logConfigIfDebug() { + log.Debugf("cfg.RootDir: %s", RootDir) + log.Debugf("viper settings %+v", viper.AllSettings()) +} + func fixConfigOptions() { if Cfg.Cookie.MaxAge > Cfg.JWT.MaxAge { @@ -398,7 +401,8 @@ func setDefaults() { if err := viper.UnmarshalKey(Branding.LCName, &Cfg); err != nil { log.Error(err) } - log.Debugf("setDefaults from .defaults.yml %+v", Cfg) + // keep this here for development, we're still pre configurating of LogLevel + // log.Debugf("setDefaults from .defaults.yml %+v", Cfg) // bare minimum for healthcheck achieved if *CmdLine.IsHealthCheck { @@ -437,7 +441,7 @@ func claimToHeader(claim string) (string, error) { claim = Cfg.Headers.ClaimHeader + http.CanonicalHeaderKey(claim) if claim != was { log.Infof("%s.header.claims %s will be forwarded downstream in the Header %s", Branding.CcName, was, claim) - log.Debugf("nginx will popultate the variable $auth_resp_%s", strings.ReplaceAll(strings.ToLower(claim), "-", "_")) + log.Debugf("nginx will populate the variable $auth_resp_%s", strings.ReplaceAll(strings.ToLower(claim), "-", "_")) } // log.Errorf("%s.header.claims %s will be forwarded in the Header %s", Branding.CcName, was, claim) return claim, nil From 59bc89f02994356171f645e19ce1d4b8b50a5bd6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 1 Jun 2020 14:17:34 -0700 Subject: [PATCH 436/736] fix #277 set google redirecturl during config --- config/testing/handler_login_redirecturls.yml | 19 ++++++++ handlers/login_test.go | 44 +++++++++++++++++++ pkg/cfg/cfg_test.go | 3 -- pkg/cfg/oauth.go | 1 + 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 config/testing/handler_login_redirecturls.yml diff --git a/config/testing/handler_login_redirecturls.yml b/config/testing/handler_login_redirecturls.yml new file mode 100644 index 00000000..c29fa794 --- /dev/null +++ b/config/testing/handler_login_redirecturls.yml @@ -0,0 +1,19 @@ +vouch: + domains: + - example.com + - other.com + + cookie: + secure: false + + jwt: + secret: testingsecret + +oauth: + provider: google + client_id: 1234567 + client_secret: testingsecret + auth_url: https://indielogin.com/auth + callback_urls: + - http://vouch.example.com:9090/auth + - http://vouch.other.com:9090/auth diff --git a/handlers/login_test.go b/handlers/login_test.go index a0d98c65..fd88f264 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -12,8 +12,12 @@ package handlers import ( "net/http" + "net/http/httptest" "net/url" "testing" + + "github.com/stretchr/testify/assert" + "github.com/vouch/vouch-proxy/pkg/cfg" ) func Test_getValidRequestedURL(t *testing.T) { @@ -53,3 +57,43 @@ func Test_getValidRequestedURL(t *testing.T) { }) } } + +func TestLoginHandler(t *testing.T) { + handler := http.HandlerFunc(LoginHandler) + + tests := []struct { + name string + configFile string + wantcode int + }{ + {"general test", "/config/testing/handler_login_url.yml", http.StatusFound}, + {"general test", "/config/testing/handler_login_redirecturls.yml", http.StatusFound}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setUp(tt.configFile) + + req, err := http.NewRequest("GET", "/logout?url=http://myapp.example.com/login", nil) + if err != nil { + t.Fatal(err) + } + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + if rr.Code != tt.wantcode { + t.Errorf("LogoutHandler() status = %v, want %v", rr.Code, tt.wantcode) + } + + // confirm the OAuthClient has a properly configured + redirectURL, err := url.Parse(rr.Header()["Location"][0]) + if err != nil { + t.Fatal(err) + } + redirectParam := redirectURL.Query().Get("redirect_uri") + assert.NotEmpty(t, cfg.OAuthClient.RedirectURL, "cfg.OAuthClient.RedirectURL is empty") + assert.NotEmpty(t, redirectParam, "redirect_uri should not be empty when redirected to google oauth") + + }) + } +} diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 371d4ca1..7be55b74 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -154,7 +154,6 @@ func Test_configureFromEnvCfg(t *testing.T) { tests := []struct { name string }{ - // TODO: Add test cases. {"Cfg struct field should be populated from env var"}, } for _, tt := range tests { @@ -226,7 +225,6 @@ func Test_configureFromEnvOAuth(t *testing.T) { tests := []struct { name string }{ - // TODO: Add test cases. {"OAuth struct field should be populated from env var"}, } for _, tt := range tests { @@ -246,5 +244,4 @@ func cleanupEnv() { os.Setenv(Branding.UCName+"_ROOT", RootDir) Cfg = &Config{} GenOAuth = &oauthConfig{} - } diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 421b85f1..c6d0f7c7 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -153,6 +153,7 @@ func setDefaultsGoogle() { ClientSecret: GenOAuth.ClientSecret, Scopes: GenOAuth.Scopes, Endpoint: google.Endpoint, + RedirectURL: GenOAuth.RedirectURL, } if GenOAuth.PreferredDomain != "" { log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) From b15b247b17fc2c7e302b40080ed4f7eb3f40f5bf Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 1 Jun 2020 14:26:23 -0700 Subject: [PATCH 437/736] #277 log OAuth config --- do.sh | 2 +- pkg/cfg/cfg.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/do.sh b/do.sh index 3271c6a6..a4e3e44e 100755 --- a/do.sh +++ b/do.sh @@ -129,7 +129,7 @@ _redact_exit () { } _redact() { - SECRET_FIELDS=("client_id client_secret secret") + SECRET_FIELDS=("client_id client_secret secret ClientSecret ClientID") while IFS= read -r LINE; do for i in $SECRET_FIELDS; do LINE=$(echo "$LINE" | sed -r "s/${i}..[[:graph:]]*\>/${i}: XXXXXXXXXXX/g") diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 68a0d4b6..83002acf 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -281,6 +281,7 @@ func parseConfigFile() error { func logConfigIfDebug() { log.Debugf("cfg.RootDir: %s", RootDir) log.Debugf("viper settings %+v", viper.AllSettings()) + log.Debugf("cfg.GenOauth %+v", GenOAuth) } func fixConfigOptions() { From 296fe1a424688c3cbfa11083a0b8e6f35146fa3e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 1 Jun 2020 14:31:48 -0700 Subject: [PATCH 438/736] fix misspellings --- handlers/login.go | 2 +- pkg/cfg/cfg_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index cc752d6d..86940e83 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -172,7 +172,7 @@ func oauthLoginURL(r *http.Request, state string) string { lurl = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) } else { // cfg.OAuthClient.RedirectURL is set in cfg - // this checks the multiple redirect case for mulitple matching domains + // this checks the multiple redirect case for multiple matching domains if len(cfg.GenOAuth.RedirectURLs) > 0 { found := false domain := domains.Matches(r.Host) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 7be55b74..d6dfb660 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -117,7 +117,7 @@ func Test_configureFromEnvCfg(t *testing.T) { for _, v := range senv { os.Setenv(v, svalue) } - // "VOUCH_LOGLEVEL" is special since logging is occuring during these tests, needs to be an actual level + // "VOUCH_LOGLEVEL" is special since logging is occurring during these tests, needs to be an actual level os.Setenv("VOUCH_LOGLEVEL", "debug") savalue := []string{"arrayone", "arraytwo", "arraythree"} From 4a99f11af10e80766dc472b6ebbf5eeeb160f88b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sun, 7 Jun 2020 14:07:58 -0700 Subject: [PATCH 439/736] fix #278 check for cancel before cacheing --- handlers/validate_test.go | 40 ++++++++++++++++++++++++---------- pkg/cfg/cfg.go | 4 ++++ pkg/jwtmanager/jwtcache.go | 44 ++++++-------------------------------- pkg/responses/responses.go | 23 +++++++++++++++----- 4 files changed, 58 insertions(+), 53 deletions(-) diff --git a/handlers/validate_test.go b/handlers/validate_test.go index 5188f4a0..7d82a3f1 100644 --- a/handlers/validate_test.go +++ b/handlers/validate_test.go @@ -209,12 +209,14 @@ func TestJWTCacheHandler(t *testing.T) { tokens := structs.PTokens{} customClaims := structs.CustomClaims{} - userTokenString := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + jwt := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + badjwt := strings.ReplaceAll(jwt, "a", "z") + badjwt = strings.ReplaceAll(badjwt, "b", "x") c := &http.Cookie{ // Name: cfg.Cfg.Cookie.Name + "_1of1", Name: cfg.Cfg.Cookie.Name, - Value: userTokenString, + Value: jwt, Expires: time.Now().Add(1 * time.Hour), Domain: cfg.Cfg.Cookie.Domain, } @@ -228,22 +230,38 @@ func TestJWTCacheHandler(t *testing.T) { } tests := []struct { - name string - cookie *http.Cookie - wantcode int + name string + cookie *http.Cookie + bearerJWT string + wantcode int }{ - {"authorized", c, http.StatusOK}, - {"authorized", c, http.StatusOK}, // because we're testing the cacheing we run these multiple times - {"notauthorized", cBlank, http.StatusUnauthorized}, - {"notauthorized", cBlank, http.StatusUnauthorized}, - {"authorized", c, http.StatusOK}, + // because we're testing the cacheing we run these multiple times + {"authorized 1", c, "", http.StatusOK}, + {"authorized 2", c, "", http.StatusOK}, + {"notauthorized 1", cBlank, "", http.StatusUnauthorized}, + {"notauthorized 2", cBlank, "", http.StatusUnauthorized}, + {"authorized 3", c, "", http.StatusOK}, + {"bearer 1", nil, jwt, http.StatusOK}, + {"badBearer 1", nil, badjwt, http.StatusUnauthorized}, + // {"badBearer", nil, badjwt, http.StatusUnauthorized}, + {"bearer 2", nil, jwt, http.StatusOK}, + {"badBearer 2", nil, badjwt, http.StatusUnauthorized}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req, err := http.NewRequest("GET", "/validate", nil) req.Host = "myapp.example.com" - req.AddCookie(tt.cookie) + + if tt.cookie != nil { + req.AddCookie(tt.cookie) + } + + // https://github.com/vouch/vouch-proxy/issues/278 + if tt.bearerJWT != "" { + req.Header.Add("Authorization", "Bearer "+tt.bearerJWT) + } + if err != nil { t.Fatal(err) } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 83002acf..364d7fe7 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -129,6 +129,10 @@ const ( // for a Base64 string we need 44 characters to get 32bytes (6 bits per char) minBase64Length = 44 base64Bytes = 32 + + // ErrCtx set or check the http request context to see if it has errored + // see `responses.Error401` and `jwtmanager.JWTCacheHandler` for example + ErrCtx = "isErr" ) // Configure called at the very top of main() diff --git a/pkg/jwtmanager/jwtcache.go b/pkg/jwtmanager/jwtcache.go index 1f24fbab..9ff85bfb 100644 --- a/pkg/jwtmanager/jwtcache.go +++ b/pkg/jwtmanager/jwtcache.go @@ -11,7 +11,6 @@ OR CONDITIONS OF ANY KIND, either express or implied. package jwtmanager import ( - "context" "net/http" "strings" "time" @@ -75,42 +74,13 @@ func JWTCacheHandler(next http.Handler) http.Handler { } } - ctx := context.Background() - next.ServeHTTP(w, r.WithContext(ctx)) - - go func() { - if jwt != "" { - // cache the response against this jwt - Cache.SetDefault(jwt, w.Header().Clone()) - } - }() + next.ServeHTTP(w, r) + if jwt != "" && + r.Context().Err() == nil { // r.Context().Done() is still open + // cache the response headers for this jwt + // log.Debug("setting cache for %+v", w.Header().Clone()) + Cache.SetDefault(jwt, w.Header().Clone()) + } }) } - -// func (cr *CachedResponse) Write(b []byte) (int, error) { -// cr.rawResponse = append(cr.rawResponse, b[:]...) -// return cr.CaptureWriter.Write(b) -// } - -// // Header calls http.Writer.Header() -// func (cr *CachedResponse) Header() http.Header { -// return cr.CaptureWriter.Header() -// } - -// // WriteHeader calls http.Writer.WriteHeader(code) -// func (cr *CachedResponse) WriteHeader(code int) { -// cr.CaptureWriter.WriteHeader(code) -// } - -// // RawDump constructs the contents to be cached -// func (cr *CachedResponse) RawDump() []byte { -// var dump bytes.Buffer -// for k, v := range cr.Header().Clone() { -// dump.WriteString(fmt.Sprintf("%s: %s", k, strings.Join(v, ","))) -// dump.WriteRune('\n') -// } -// dump.WriteRune('\n') -// dump.Write(cr.rawResponse) -// return dump.Bytes() -// } diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 55cf8593..7c823f4f 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -19,6 +19,7 @@ import ( "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" "go.uber.org/zap" + "golang.org/x/net/context" ) // Index variables passed to index.tmpl @@ -54,9 +55,9 @@ func RenderIndex(w http.ResponseWriter, msg string) { } } -// RenderError html error page +// renderError html error page // something terse for the end user -func RenderError(w http.ResponseWriter, msg string) { +func renderError(w http.ResponseWriter, msg string) { log.Debugf("rendering error for user: %s", msg) if err := indexTemplate.Execute(w, &Index{Msg: msg}); err != nil { log.Error(err) @@ -87,25 +88,37 @@ func Error400(w http.ResponseWriter, r *http.Request, e error) { cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusBadRequest) - RenderError(w, "400 Bad Request") + addErrandCancelRequest(r) + renderError(w, "400 Bad Request") } // Error401 Unauthorized the standard error // this is captured by nginx, which converts the 401 into 302 to the login page func Error401(w http.ResponseWriter, r *http.Request, e error) { log.Error(e) + addErrandCancelRequest(r) cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) http.Error(w, e.Error(), http.StatusUnauthorized) - // RenderError(w, "401 Unauthorized") + // renderError(w, "401 Unauthorized") } // Error403 Forbidden // if there's an error during /auth or if they don't pass validation in /auth func Error403(w http.ResponseWriter, r *http.Request, e error) { log.Error(e) + addErrandCancelRequest(r) cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusForbidden) - RenderError(w, "403 Forbidden") + renderError(w, "403 Forbidden") +} + +// cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler` +func addErrandCancelRequest(r *http.Request) { + ctx, cancel := context.WithCancel(r.Context()) + ctx = context.WithValue(ctx, cfg.ErrCtx, true) + *r = *r.Clone(ctx) + cancel() // we're done + return } From 881dfc2c70edfe7c4fda11907571420161f0ccc3 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Sat, 20 Jun 2020 04:21:01 -0400 Subject: [PATCH 440/736] More robust parsing of url param to login; see #281 --- handlers/login.go | 107 ++++++++++++++++++++++++++++++----------- handlers/login_test.go | 44 +++++++++++++++++ 2 files changed, 124 insertions(+), 27 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 86940e83..13aff767 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -95,41 +95,94 @@ var ( errNoURL = errors.New("no destination URL requested") errInvalidURL = errors.New("requested destination URL appears to be invalid") errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") + errLoginStrayParams = errors.New("login request included unrecognized parameters") errDangerQS = errors.New("requested destination URL has a dangerous query string") badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} ) -func getValidRequestedURL(r *http.Request) (string, error) { - // nginx is configured with... - // `return 302 https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;` - // because `url=$scheme://$http_host$request_uri` might be.. - // `url=http://protectedapp.yourdomain.com/hello?arg1=val1&arg2=val2` - // it causes `arg2=val2` to get lost if a regular evaluation of the `url` param is performedwith... - // urlparam := r.URL.Query().Get("url") - // so instead we extract in manually - - urlparam := r.URL.RawQuery - urlparam = strings.Split(urlparam, "&vouch-failcount")[0] - urlparam = strings.TrimPrefix(urlparam, "url=") - log.Debugf("raw URL is %s", urlparam) - - // urlparam := r.URL.Query().Get("url") - // log.Debugf("url URL is %s", urlparam) - - if urlparam == "" { - return "", errNoURL +// Inspect login query params to located the url param, while taking into account that the login URL may be +// presented in an RFC-non-compliant way (for example, it is common for the url param to +// not have its own query params property encoded, leading to URLs like +// http://host/login?X-Vouch-Token=token&url=http://host/path?param=value¶m2=value2&vouch-failcount=value3 +// where some params -- here X-Vouch-Token and vouch-failcount -- belong to login, and some others +// -- here param and param2 -- belong to the url param of login) +// The algorithm is as follows: +// * All login params starting with vouch- or x-vouch- (case insensitively) are treated as true login params +// * All other login params are treated as non-login params +// * All non-login params between the url param and the first true login param are folded into the url param +// * All remaining non-login params are considered stray non-login params +// * Error is returned if the url cannot be parsed *or* it contains stray non-login params +// * For the benefit of unit-testing, if the url contains stray non-login params, it's +// returned anyway (in addition to error return) +func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { + // url.URL.Query return a map and therefore makes no guarantees about param order + // Therefore we have to ascertain the param order by inspecting the raw query + var urlParam *url.URL = nil // Will be url.URL for the url param + strayParams := false // Will be true if stray params are found + urlParamDone := false // Will be true when we're done building urlParam (but we're still checking for stray params) + + for _, param := range strings.Split(loginURL.RawQuery, "&") { + paramKeyVal := strings.Split(param, "=") + paramKey := paramKeyVal[0] + lcParamKey := strings.ToLower(paramKey) + isVouchParam := strings.HasPrefix(lcParamKey, "vouch-") || strings.HasPrefix(lcParamKey, "x-vouch-") + + if urlParam == nil { + // Still looking for url param + if paramKey == "url" { + // Found it + parsed, e := url.Parse(loginURL.Query().Get("url")) + if e != nil { + return nil, e // Straight up failure to parse url param + } + + urlParam = parsed + } else if !isVouchParam { + // Non-vouch param before url param is a stray param + strayParams = true + } // else vouch param before url param, doesn't change outcome + } else { + // Looking at params after url param + if !urlParamDone && isVouchParam { + // First vouch param after url param + urlParamDone = true + // But keep going to check for strays + } else if !urlParamDone { + // Non-vouch param after url and before first vouch param, fold it into urlParam + if urlParam.RawQuery == "" { + urlParam.RawQuery = param + } else { + urlParam.RawQuery = urlParam.RawQuery + "&" + param + } + } else { + // Non-vouch param after vouch param is a stray param + strayParams = true + } + } } - if !strings.HasPrefix(strings.ToLower(urlparam), "http://") && !strings.HasPrefix(strings.ToLower(urlparam), "https://") { - return "", errURLNotHTTP + + // Check if there were stray parameters to decide whether to return an error + if strayParams { + return urlParam, errLoginStrayParams + } else { + return urlParam, nil } - u, err := url.Parse(urlparam) + +} + +func getValidRequestedURL(r *http.Request) (string, error) { + u, err := normalizeLoginURLParam(r.URL) + if err != nil { - return "", fmt.Errorf("won't parse: %w %s", errInvalidURL, err) + return "", fmt.Errorf("Not a valid login URL: %w %s", errInvalidURL, err) } - _, err = url.ParseQuery(u.RawQuery) - if err != nil { - return "", fmt.Errorf("query string won't parse: %w %s", errInvalidURL, err) + if u == nil { + return "", errNoURL + } + + if u.Scheme != "http" && u.Scheme != "https" { + return "", errURLNotHTTP } for _, v := range u.Query() { @@ -158,7 +211,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { return "", fmt.Errorf("%w: mismatch between requested destination URL and '%s.cookie.secure: %v' (the cookie is only visible to 'https' but the requested site is 'http')", errInvalidURL, cfg.Branding.LCName, cfg.Cfg.Cookie.Secure) } - return urlparam, nil + return u.String(), nil } func oauthLoginURL(r *http.Request, state string) string { diff --git a/handlers/login_test.go b/handlers/login_test.go index fd88f264..14385de6 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -20,6 +20,50 @@ import ( "github.com/vouch/vouch-proxy/pkg/cfg" ) +func Test_normalizeLoginURL(t *testing.T) { + setUp("/config/testing/handler_login_url.yml") + tests := []struct { + name string + url string + want string + wantErr bool + }{ + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + {"extra params", "http://host/login?url=http://host/path&p2=2", "http://host/path?p2=2", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though the p1 param is not a login param, we do not interpret is as part of the url param because it precedes it + {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", true}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume vouch-* is a login param and do not fold it into url + {"vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume x-vouch-* is a login param and do not fold it into url + {"x-vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (vouch-*) + {"params after vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2&p3=3", "http://host/path", true}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (x-vouch-*) + {"params after x-vouch-* params", "http://host/login?url=http://host/path&x-vouch-xxx=2&p3=3", "http://host/path", true}, + // This is not an RFC-compliant URL; it combines all the aspects above + {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + // This is an RFC-compliant URL + {"all params", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + u, _ := url.Parse(tt.url) + got, err := normalizeLoginURLParam(u) + if got.String() != tt.want { + t.Errorf("normalizeLoginURLParam() = %v, want %v", got, tt.want) + } + if (err != nil) != tt.wantErr { + t.Errorf("normalizeLoginURLParam() err = %v", err) + } + }) + } +} + func Test_getValidRequestedURL(t *testing.T) { setUp("/config/testing/handler_login_url.yml") r := &http.Request{} From 5b4c71d9b0af239936f76501968a9611ee86b317 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Tue, 23 Jun 2020 16:59:05 -0400 Subject: [PATCH 441/736] Unambiguous test name --- handlers/login_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/login_test.go b/handlers/login_test.go index 14385de6..67f32ae6 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -48,7 +48,7 @@ func Test_normalizeLoginURL(t *testing.T) { // This is not an RFC-compliant URL; it combines all the aspects above {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, // This is an RFC-compliant URL - {"all params", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From f27d4b1df5cad32518ad5ecccce9284147512185 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Tue, 23 Jun 2020 16:59:31 -0400 Subject: [PATCH 442/736] Added tests for the case of vouch param before url param --- handlers/login_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/handlers/login_test.go b/handlers/login_test.go index 67f32ae6..b8293c5a 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -35,10 +35,16 @@ func Test_normalizeLoginURL(t *testing.T) { {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", true}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume vouch-* is a login param and do not fold it into url - {"vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + {"vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume vouch-* is a login param and do not fold it into url + {"vouch-* params before", "http://host/login?vouch-xxx=1&url=http://host/path", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume x-vouch-* is a login param and do not fold it into url + {"x-vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume x-vouch-* is a login param and do not fold it into url - {"x-vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + {"x-vouch-* params before", "http://host/login?x-vouch-xxx=1&url=http://host/path", "http://host/path", false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (vouch-*) {"params after vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2&p3=3", "http://host/path", true}, From ddbea36d37c78341d29e0dd8e17b160b9b28e698 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Tue, 23 Jun 2020 17:23:25 -0400 Subject: [PATCH 443/736] Allow semicolon as param separator in URL https://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2 --- handlers/login.go | 2 +- handlers/login_test.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/handlers/login.go b/handlers/login.go index 13aff767..c7c717b1 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -121,7 +121,7 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { strayParams := false // Will be true if stray params are found urlParamDone := false // Will be true when we're done building urlParam (but we're still checking for stray params) - for _, param := range strings.Split(loginURL.RawQuery, "&") { + for _, param := range regexp.MustCompile("[&;]").Split(loginURL.RawQuery, -1) { paramKeyVal := strings.Split(param, "=") paramKey := paramKeyVal[0] lcParamKey := strings.ToLower(paramKey) diff --git a/handlers/login_test.go b/handlers/login_test.go index b8293c5a..d74bd56b 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -55,6 +55,11 @@ func Test_normalizeLoginURL(t *testing.T) { {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, // This is an RFC-compliant URL {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + // This is not an RFC-compliant URL; it combines all the aspects above, and it uses semicolons as parameter separators + // Note that when we fold a stray param into the url param, we always do so with &s + {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", true}, + // This is an RFC-compliant URL that uses semicolons as parameter separators + {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From c1b37a7da943b61a0646558c606425ed5ee8d995 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 24 Jun 2020 12:17:02 -0700 Subject: [PATCH 444/736] #281 add tests for README 302 syntax --- handlers/login_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/handlers/login_test.go b/handlers/login_test.go index d74bd56b..2ffc5d23 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -28,8 +28,13 @@ func Test_normalizeLoginURL(t *testing.T) { want string wantErr bool }{ + // the documentation since v0.4.0 has shown this URL in the README as the 302 redirect + {"as per README", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, + {"as per README (blanks)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, + {"as per README (blanks, mixed with semi)", "http://host/login?url=http://host/path?p2=2;p=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway - {"extra params", "http://host/login?url=http://host/path&p2=2", "http://host/path?p2=2", false}, + {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", false}, + {"extra params (blank)", "http://host/login?url=http://host/path?p2=", "http://host/path?p2=", false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // Even though the p1 param is not a login param, we do not interpret is as part of the url param because it precedes it {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", true}, @@ -88,6 +93,7 @@ func Test_getValidRequestedURL(t *testing.T) { {"redirection chaining", "http://example.com/dest?url=https://", "", true}, {"redirection chaining upper case", "http://example.com/dest?url=HTTPS://someplaceelse.com", "", true}, {"redirection chaining no protocol", "http://example.com/dest?url=//someplaceelse.com", "", true}, + {"redirection chaining escaped https://", "http://example.com/dest?url=https%3a%2f%2fsomeplaceelse.com", "", true}, {"data uri", "http://example.com/dest?url=data:text/plain,Example+Text", "", true}, {"javascript uri", "http://example.com/dest?url=javascript:alert(1)", "", true}, {"not in domain", "http://somewherelse.com/", "", true}, @@ -95,8 +101,7 @@ func Test_getValidRequestedURL(t *testing.T) { {"should be fine", "http://example.com/", "http://example.com/", false}, {"multiple query param", "http://example.com/?strange=but-true&also-strange=but-false", "http://example.com/?strange=but-true&also-strange=but-false", false}, {"multiple query params, one of them bad", "http://example.com/?strange=but-true&also-strange=but-false&strange-but-bad=https://badandstrange.com", "", true}, - - // TODO: Add test cases. + {"multiple query params, one of them bad (escaped)", "http://example.com/?strange=but-true&also-strange=but-false&strange-but-bad=https%3a%2f%2fbadandstrange.com", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From dabee5c27efb106de99a60c9e9651eab11287583 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 25 Jun 2020 12:28:32 -0400 Subject: [PATCH 445/736] Log about url normalization --- handlers/login.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/handlers/login.go b/handlers/login.go index c7c717b1..adbf5449 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -139,6 +139,7 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { urlParam = parsed } else if !isVouchParam { // Non-vouch param before url param is a stray param + log.Infof("Stray param in login request (%s)", paramKey) strayParams = true } // else vouch param before url param, doesn't change outcome } else { @@ -156,12 +157,14 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { } } else { // Non-vouch param after vouch param is a stray param + log.Infof("Stray param in login request (%s)", paramKey) strayParams = true } } } // Check if there were stray parameters to decide whether to return an error + log.Debugf("Login url param normalized to '%s'", urlParam.String()) if strayParams { return urlParam, errLoginStrayParams } else { From e50e1aa44058dd75f7cdf8cd9d69f61ab45b6dca Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 25 Jun 2020 12:29:16 -0400 Subject: [PATCH 446/736] Clarified README unit tests --- handlers/login_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/handlers/login_test.go b/handlers/login_test.go index 2ffc5d23..168c1c92 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -28,10 +28,6 @@ func Test_normalizeLoginURL(t *testing.T) { want string wantErr bool }{ - // the documentation since v0.4.0 has shown this URL in the README as the 302 redirect - {"as per README", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, - {"as per README (blanks)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, - {"as per README (blanks, mixed with semi)", "http://host/login?url=http://host/path?p2=2;p=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", false}, {"extra params (blank)", "http://host/login?url=http://host/path?p2=", "http://host/path?p2=", false}, @@ -65,6 +61,11 @@ func Test_normalizeLoginURL(t *testing.T) { {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", true}, // This is an RFC-compliant URL that uses semicolons as parameter separators {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", true}, + // Real world tests + // There are from vouch README since c0.4.0 (recommended nginx setting for 302 redirect) + {"Vouch README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, + {"Vouch README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, + {"Vouch README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From dfc6cb33a74f64b44b2c4d0d7caed4c22f96df5e Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 25 Jun 2020 12:59:24 -0400 Subject: [PATCH 447/736] =?UTF-8?q?Allow=20=E2=80=98error=E2=80=99=20param?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handlers/login.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handlers/login.go b/handlers/login.go index adbf5449..b1136367 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -108,6 +108,7 @@ var ( // -- here param and param2 -- belong to the url param of login) // The algorithm is as follows: // * All login params starting with vouch- or x-vouch- (case insensitively) are treated as true login params +// * The "error" login param (case sensitively) is treated as true login param // * All other login params are treated as non-login params // * All non-login params between the url param and the first true login param are folded into the url param // * All remaining non-login params are considered stray non-login params @@ -125,7 +126,7 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { paramKeyVal := strings.Split(param, "=") paramKey := paramKeyVal[0] lcParamKey := strings.ToLower(paramKey) - isVouchParam := strings.HasPrefix(lcParamKey, "vouch-") || strings.HasPrefix(lcParamKey, "x-vouch-") + isVouchParam := strings.HasPrefix(lcParamKey, "vouch-") || strings.HasPrefix(lcParamKey, "x-vouch-") || paramKey == "error" if urlParam == nil { // Still looking for url param From 4adbaadf2870dc9381a8e62cc79ca218aff0a2e7 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 25 Jun 2020 12:57:06 -0400 Subject: [PATCH 448/736] Fixed handling of multiple vouch params in login request --- handlers/login.go | 4 ++-- handlers/login_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index b1136367..9e2a6a38 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -156,11 +156,11 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { } else { urlParam.RawQuery = urlParam.RawQuery + "&" + param } - } else { + } else if !isVouchParam { // Non-vouch param after vouch param is a stray param log.Infof("Stray param in login request (%s)", paramKey) strayParams = true - } + } // else vouch param after vouch param, doesn't change outcome } } diff --git a/handlers/login_test.go b/handlers/login_test.go index 168c1c92..6191e8e6 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -53,9 +53,9 @@ func Test_normalizeLoginURL(t *testing.T) { // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (x-vouch-*) {"params after x-vouch-* params", "http://host/login?url=http://host/path&x-vouch-xxx=2&p3=3", "http://host/path", true}, // This is not an RFC-compliant URL; it combines all the aspects above - {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, // This is an RFC-compliant URL - {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&p5=5", "http://host/path?p2=2&p3=3", true}, + {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, // This is not an RFC-compliant URL; it combines all the aspects above, and it uses semicolons as parameter separators // Note that when we fold a stray param into the url param, we always do so with &s {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", true}, From 054bff3fdfc8870c208eb5a5711b7e937cfc200c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 25 Jun 2020 13:25:58 -0700 Subject: [PATCH 449/736] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit aed84160d4b9737d09b127a2c022afda83e1cfd9 Author: Benjamin Foote Date: Thu Jun 25 13:23:31 2020 -0700 #281 gofmt, minor edits commit c38b05da608becb4cc59666ce650e38002799cbd Author: Benjamin Foote Date: Thu Jun 25 13:23:15 2020 -0700 #281 compile regex once, use cfg.Branding commit d9cb3f6005e043a31292930c66d336e87447f11c Author: Benjamin Foote Date: Thu Jun 25 13:20:01 2020 -0700 error on empty URL commit 4adbaadf2870dc9381a8e62cc79ca218aff0a2e7 Author: Ben Artin Date: Thu Jun 25 12:57:06 2020 -0400 Fixed handling of multiple vouch params in login request commit dfc6cb33a74f64b44b2c4d0d7caed4c22f96df5e Author: Ben Artin Date: Thu Jun 25 12:59:24 2020 -0400 Allow ‘error’ param commit e50e1aa44058dd75f7cdf8cd9d69f61ab45b6dca Author: Ben Artin Date: Thu Jun 25 12:29:16 2020 -0400 Clarified README unit tests commit dabee5c27efb106de99a60c9e9651eab11287583 Author: Ben Artin Date: Thu Jun 25 12:28:32 2020 -0400 Log about url normalization commit c1b37a7da943b61a0646558c606425ed5ee8d995 Author: Benjamin Foote Date: Wed Jun 24 12:17:02 2020 -0700 #281 add tests for README 302 syntax commit ddbea36d37c78341d29e0dd8e17b160b9b28e698 Author: Ben Artin Date: Tue Jun 23 17:23:25 2020 -0400 Allow semicolon as param separator in URL https://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2 commit f27d4b1df5cad32518ad5ecccce9284147512185 Author: Ben Artin Date: Tue Jun 23 16:59:31 2020 -0400 Added tests for the case of vouch param before url param commit 5b4c71d9b0af239936f76501968a9611ee86b317 Author: Ben Artin Date: Tue Jun 23 16:59:05 2020 -0400 Unambiguous test name commit 881dfc2c70edfe7c4fda11907571420161f0ccc3 Author: Ben Artin Date: Sat Jun 20 04:21:01 2020 -0400 More robust parsing of url param to login; see #281 --- handlers/login.go | 121 ++++++++++++++++++++++++++++++----------- handlers/login_test.go | 65 +++++++++++++++++++++- 2 files changed, 152 insertions(+), 34 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 86940e83..eee75a97 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -92,44 +92,101 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { } var ( - errNoURL = errors.New("no destination URL requested") - errInvalidURL = errors.New("requested destination URL appears to be invalid") - errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") - errDangerQS = errors.New("requested destination URL has a dangerous query string") - badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} + errNoURL = errors.New("no destination URL requested") + errInvalidURL = errors.New("requested destination URL appears to be invalid") + errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") + errLoginStrayParams = errors.New("login request included unrecognized parameters") + errDangerQS = errors.New("requested destination URL has a dangerous query string") + badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} + reAmpSemi = regexp.MustCompile("[&;]") ) -func getValidRequestedURL(r *http.Request) (string, error) { - // nginx is configured with... - // `return 302 https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;` - // because `url=$scheme://$http_host$request_uri` might be.. - // `url=http://protectedapp.yourdomain.com/hello?arg1=val1&arg2=val2` - // it causes `arg2=val2` to get lost if a regular evaluation of the `url` param is performedwith... - // urlparam := r.URL.Query().Get("url") - // so instead we extract in manually - - urlparam := r.URL.RawQuery - urlparam = strings.Split(urlparam, "&vouch-failcount")[0] - urlparam = strings.TrimPrefix(urlparam, "url=") - log.Debugf("raw URL is %s", urlparam) - - // urlparam := r.URL.Query().Get("url") - // log.Debugf("url URL is %s", urlparam) - - if urlparam == "" { - return "", errNoURL +// inspect login query params to located the url param, while taking into account that the login URL may be +// presented in an RFC-non-compliant way (for example, it is common for the url param to +// not have its own query params property encoded, leading to URLs like +// http://host/login?X-Vouch-Token=token&url=http://host/path?param=value¶m2=value2&vouch-failcount=value3 +// where some params -- here X-Vouch-Token and vouch-failcount -- belong to login, and some others +// -- here param and param2 -- belong to the url param of login) +// The algorithm is as follows: +// * All login params starting with vouch- or x-vouch- (case insensitively) are treated as true login params +// * The "error" login param (case sensitively) is treated as true login param +// * All other login params are treated as non-login params +// * All non-login params between the url param and the first true login param are folded into the url param +// * All remaining non-login params are considered stray non-login params +// * Error is returned if the url cannot be parsed *or* it contains stray non-login params +// * For the benefit of unit-testing, if the url contains stray non-login params, it's +// returned anyway (in addition to error return) +func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { + // url.URL.Query return a map and therefore makes no guarantees about param order + // Therefore we have to ascertain the param order by inspecting the raw query + var urlParam *url.URL = nil // Will be url.URL for the url param + strayParams := false // Will be true if stray params are found + urlParamDone := false // Will be true when we're done building urlParam (but we're still checking for stray params) + + for _, param := range reAmpSemi.Split(loginURL.RawQuery, -1) { + paramKeyVal := strings.Split(param, "=") + paramKey := paramKeyVal[0] + lcParamKey := strings.ToLower(paramKey) + isVouchParam := strings.HasPrefix(lcParamKey, cfg.Branding.LCName) || strings.HasPrefix(lcParamKey, "x-"+cfg.Branding.LCName) || paramKey == "error" + + if urlParam == nil { + // Still looking for url param + if paramKey == "url" { + // Found it + parsed, e := url.Parse(loginURL.Query().Get("url")) + if e != nil { + return nil, e // failure to parse url param + } + + urlParam = parsed + } else if !isVouchParam { + // Non-vouch param before url param is a stray param + log.Infof("Stray param in login request (%s)", paramKey) + strayParams = true + } // else vouch param before url param, doesn't change outcome + } else { + // Looking at params after url param + if !urlParamDone && isVouchParam { + // First vouch param after url param + urlParamDone = true + // But keep going to check for strays + } else if !urlParamDone { + // Non-vouch param after url and before first vouch param, fold it into urlParam + if urlParam.RawQuery == "" { + urlParam.RawQuery = param + } else { + urlParam.RawQuery = urlParam.RawQuery + "&" + param + } + } else if !isVouchParam { + // Non-vouch param after vouch param is a stray param + log.Infof("Stray param in login request (%s)", paramKey) + strayParams = true + } // else vouch param after vouch param, doesn't change outcome + } } - if !strings.HasPrefix(strings.ToLower(urlparam), "http://") && !strings.HasPrefix(strings.ToLower(urlparam), "https://") { - return "", errURLNotHTTP + + // if there were stray parameters return an error + log.Debugf("Login url param normalized to '%s'", urlParam) + if strayParams { + return urlParam, errLoginStrayParams } - u, err := url.Parse(urlparam) + return urlParam, nil + +} + +func getValidRequestedURL(r *http.Request) (string, error) { + u, err := normalizeLoginURLParam(r.URL) + if err != nil { - return "", fmt.Errorf("won't parse: %w %s", errInvalidURL, err) + return "", fmt.Errorf("Not a valid login URL: %w %s", errInvalidURL, err) } - _, err = url.ParseQuery(u.RawQuery) - if err != nil { - return "", fmt.Errorf("query string won't parse: %w %s", errInvalidURL, err) + if u == nil || u.String() == "" { + return "", errNoURL + } + + if u.Scheme != "http" && u.Scheme != "https" { + return "", errURLNotHTTP } for _, v := range u.Query() { @@ -158,7 +215,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { return "", fmt.Errorf("%w: mismatch between requested destination URL and '%s.cookie.secure: %v' (the cookie is only visible to 'https' but the requested site is 'http')", errInvalidURL, cfg.Branding.LCName, cfg.Cfg.Cookie.Secure) } - return urlparam, nil + return u.String(), nil } func oauthLoginURL(r *http.Request, state string) string { diff --git a/handlers/login_test.go b/handlers/login_test.go index fd88f264..b0688e9e 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -20,6 +20,67 @@ import ( "github.com/vouch/vouch-proxy/pkg/cfg" ) +func Test_normalizeLoginURL(t *testing.T) { + setUp("/config/testing/handler_login_url.yml") + tests := []struct { + name string + url string + want string + wantErr bool + }{ + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", false}, + {"extra params (blank)", "http://host/login?url=http://host/path?p2=", "http://host/path?p2=", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though the p1 param is not a login param, we do not interpret is as part of the url param because it precedes it + {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", true}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume vouch-* is a login param and do not fold it into url + {"vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume vouch-* is a login param and do not fold it into url + {"vouch-* params before", "http://host/login?vouch-xxx=1&url=http://host/path", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume x-vouch-* is a login param and do not fold it into url + {"x-vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // We assume x-vouch-* is a login param and do not fold it into url + {"x-vouch-* params before", "http://host/login?x-vouch-xxx=1&url=http://host/path", "http://host/path", false}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (vouch-*) + {"params after vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2&p3=3", "http://host/path", true}, + // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway + // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (x-vouch-*) + {"params after x-vouch-* params", "http://host/login?url=http://host/path&x-vouch-xxx=2&p3=3", "http://host/path", true}, + // This is not an RFC-compliant URL; it combines all the aspects above + {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, + // This is an RFC-compliant URL + {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, + // This is not an RFC-compliant URL; it combines all the aspects above, and it uses semicolons as parameter separators + // Note that when we fold a stray param into the url param, we always do so with &s + {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", true}, + // This is an RFC-compliant URL that uses semicolons as parameter separators + {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", true}, + // Real world tests + // since v0.4.0 the vouch README has specified an Nginx config including a 302 redirect in the following format... + {"Vouch README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, + {"Vouch README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, + {"Vouch README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + u, _ := url.Parse(tt.url) + got, err := normalizeLoginURLParam(u) + if got.String() != tt.want { + t.Errorf("normalizeLoginURLParam() = %v, want %v", got, tt.want) + } + if (err != nil) != tt.wantErr { + t.Errorf("normalizeLoginURLParam() err = %v", err) + } + }) + } +} + func Test_getValidRequestedURL(t *testing.T) { setUp("/config/testing/handler_login_url.yml") r := &http.Request{} @@ -33,6 +94,7 @@ func Test_getValidRequestedURL(t *testing.T) { {"redirection chaining", "http://example.com/dest?url=https://", "", true}, {"redirection chaining upper case", "http://example.com/dest?url=HTTPS://someplaceelse.com", "", true}, {"redirection chaining no protocol", "http://example.com/dest?url=//someplaceelse.com", "", true}, + {"redirection chaining escaped https://", "http://example.com/dest?url=https%3a%2f%2fsomeplaceelse.com", "", true}, {"data uri", "http://example.com/dest?url=data:text/plain,Example+Text", "", true}, {"javascript uri", "http://example.com/dest?url=javascript:alert(1)", "", true}, {"not in domain", "http://somewherelse.com/", "", true}, @@ -40,8 +102,7 @@ func Test_getValidRequestedURL(t *testing.T) { {"should be fine", "http://example.com/", "http://example.com/", false}, {"multiple query param", "http://example.com/?strange=but-true&also-strange=but-false", "http://example.com/?strange=but-true&also-strange=but-false", false}, {"multiple query params, one of them bad", "http://example.com/?strange=but-true&also-strange=but-false&strange-but-bad=https://badandstrange.com", "", true}, - - // TODO: Add test cases. + {"multiple query params, one of them bad (escaped)", "http://example.com/?strange=but-true&also-strange=but-false&strange-but-bad=https%3a%2f%2fbadandstrange.com", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From d83313735b9e1612212f1ca01260845c02a3b0b5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 25 Jun 2020 13:45:45 -0700 Subject: [PATCH 450/736] Squashed commit of the following: commit a3e33f9af772505552585ef5c74b42bc2b78342c Merge: 0ea425f 054bff3 Author: Benjamin Foote Date: Thu Jun 25 13:44:23 2020 -0700 Merge branch 'master' into pr/yaws-k/279 commit 0ea425fa4690eadd3d0ba772584dad82aba00adf Author: Benjamin Foote Date: Thu Jun 25 13:44:12 2020 -0700 #266 clarify protected domain commit 2b68660fdcf2d913e1689e9723ccf682cfe173eb Author: Yosuke Kato <55400564+yaws-k@users.noreply.github.com> Date: Sun Jun 14 14:27:22 2020 +0900 Add vouch.cookie.domain description to allAllUsers configuration. --- config/config.yml_example | 1 + config/config.yml_example_oidc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/config/config.yml_example b/config/config.yml_example index 22cb965a..aa726fbd 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -34,6 +34,7 @@ vouch: # Set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider - VOUCH_ALLOWALLUSERS # allowAllUsers: false + # vouch.cookie.domain must be set below when enabling allowAllUsers # Setting publicAccess: true will accept all requests, even without a cookie. - VOUCH_PUBLICACCESS # If the user is logged in, the cookie will be validated and the user header will be set. diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc index 16b231ad..ce6c9ba7 100644 --- a/config/config.yml_example_oidc +++ b/config/config.yml_example_oidc @@ -13,7 +13,10 @@ vouch: # - OR - # instead of setting specific domains you may prefer to allow all users... # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # and set vouch.cookie.domain to the domain you wish to protect # allowAllUsers: true + # cookie: + # domain: yourdomain.com oauth: # Generic OpenID Connect From e3e1a047e4b97b975fa33728e84b815268eb3891 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 25 Jun 2020 13:58:59 -0700 Subject: [PATCH 451/736] #282 error out after six failed login attempts --- handlers/login.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/handlers/login.go b/handlers/login.go index eee75a97..59077443 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -28,6 +28,8 @@ import ( var errTooManyRedirects = errors.New("too many redirects for requested URL") +const failCountLimit = 6 + // LoginHandler /login // currently performs a 302 redirect to Google func LoginHandler(w http.ResponseWriter, r *http.Request) { @@ -78,7 +80,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { log.Error(err) } - if failcount > 2 { + if failcount > failCountLimit { var vouchError = r.URL.Query().Get("error") responses.Error400(w, r, fmt.Errorf("/login %w for %s - %s", errTooManyRedirects, requestedURL, vouchError)) return From a1cd27f5f2eec892d315f8521dff685c1518cf6a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 25 Jun 2020 14:10:07 -0700 Subject: [PATCH 452/736] add security policy --- SECURITY.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..1308f7bc --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Reporting a Vulnerability + +If you have discovered a vulnerability in Vouch Proxy DO NOT post an issue on GitHub. + +Please do email the maintainers at vouch-proxy-security@bnf.net + +We will respond in short order (usually within a day or two). From 9f70c892e7272423e3b898ac20c7c0252babf33e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 2 Jul 2020 16:08:22 -0700 Subject: [PATCH 453/736] fix #282 improve errToManyRedirects improve the error message test that the error is triggered --- handlers/login.go | 5 +++-- handlers/login_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 59077443..c84ddde3 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -26,7 +26,8 @@ import ( "golang.org/x/oauth2" ) -var errTooManyRedirects = errors.New("too many redirects for requested URL") +// see https://github.com/vouch/vouch-proxy/issues/282 +var errTooManyRedirects = errors.New("Too many unsuccessful authorization attempts for the requested URL") const failCountLimit = 6 @@ -82,7 +83,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { if failcount > failCountLimit { var vouchError = r.URL.Query().Get("error") - responses.Error400(w, r, fmt.Errorf("/login %w for %s - %s", errTooManyRedirects, requestedURL, vouchError)) + responses.Error400(w, r, fmt.Errorf("/login %w %s %s", errTooManyRedirects, requestedURL, vouchError)) return } diff --git a/handlers/login_test.go b/handlers/login_test.go index b0688e9e..6317720b 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -158,3 +158,43 @@ func TestLoginHandler(t *testing.T) { }) } } +func TestLoginErrTooManyRedirects(t *testing.T) { + + handler := http.HandlerFunc(LoginHandler) + + setUp("/config/testing/handler_login_url.yml") + + tests := []struct { + name string + wantcode int + numRequests int + }{ + {"try the URL a few times", http.StatusFound, failCountLimit}, // after we make successive number of requests up to the failCountLimit `` + {"then fail ErrTooManyRedirects", http.StatusBadRequest, 1}, // then we generate the error and return `400 Bad Request` + } + + var rr *httptest.ResponseRecorder + req, err := http.NewRequest("GET", "/logout?url=http://myapp.example.com/login", nil) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + for i := 0; i < tt.numRequests; i++ { + if err != nil { + t.Fatal(err) + } + rr = httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + if rr.Code != tt.wantcode { + t.Errorf("LogoutHandler() status = %v, want %v", rr.Code, tt.wantcode) + } + + for _, c := range rr.Result().Cookies() { + req.AddCookie(c) + } + + } + + }) + } +} From 4d5d43e5ea55efb8c6f9e2dd85ea8839fce11fc8 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 7 Jul 2020 15:19:17 -0700 Subject: [PATCH 454/736] fix #289 allow `rd`param to support Nginx Ingress --- handlers/login.go | 6 +++++- handlers/login_test.go | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index c84ddde3..4779c906 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -113,6 +113,7 @@ var ( // The algorithm is as follows: // * All login params starting with vouch- or x-vouch- (case insensitively) are treated as true login params // * The "error" login param (case sensitively) is treated as true login param +// * The "rd" login param (case sensitively) added by nginx ingress is treated as true login param https://github.com/vouch/vouch-proxy/issues/289 // * All other login params are treated as non-login params // * All non-login params between the url param and the first true login param are folded into the url param // * All remaining non-login params are considered stray non-login params @@ -130,7 +131,10 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { paramKeyVal := strings.Split(param, "=") paramKey := paramKeyVal[0] lcParamKey := strings.ToLower(paramKey) - isVouchParam := strings.HasPrefix(lcParamKey, cfg.Branding.LCName) || strings.HasPrefix(lcParamKey, "x-"+cfg.Branding.LCName) || paramKey == "error" + isVouchParam := strings.HasPrefix(lcParamKey, cfg.Branding.LCName) || + strings.HasPrefix(lcParamKey, "x-"+cfg.Branding.LCName) || + paramKey == "error" || + paramKey == "rd" if urlParam == nil { // Still looking for url param diff --git a/handlers/login_test.go b/handlers/login_test.go index 6317720b..d8a529e9 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -63,9 +63,12 @@ func Test_normalizeLoginURL(t *testing.T) { {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", true}, // Real world tests // since v0.4.0 the vouch README has specified an Nginx config including a 302 redirect in the following format... - {"Vouch README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, - {"Vouch README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, - {"Vouch README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", false}, + {"Vouch Proxy README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, + {"Vouch Proxy README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, + {"Vouch Proxy README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", false}, + // Nginx Ingress controler for Kubernetes adds the parameter `rd` to these calls + // https://github.com/vouch/vouch-proxy/issues/289 + {"rd param appended by Nginx Ingress", "http://host/login?url=http://host/path?p2=2&p3=3&vouch-failcount=&X-Vouch-Token=&error=&rd=http%3a%2f%2fhost/path%3fp2=2%3bp3=3", "http://host/path?p2=2&p3=3", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From cb663bfd098de3228715174bcaf0df2ede9cfdb6 Mon Sep 17 00:00:00 2001 From: Tom Myers Date: Fri, 10 Jul 2020 16:38:09 +0100 Subject: [PATCH 455/736] add azure ad provider which maps upn claim to username/email --- handlers/handlers.go | 3 ++ pkg/cfg/oauth.go | 5 ++- pkg/providers/azure/azure.go | 82 ++++++++++++++++++++++++++++++++++++ pkg/structs/structs.go | 20 +++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 pkg/providers/azure/azure.go diff --git a/handlers/handlers.go b/handlers/handlers.go index 7831effb..2957bfef 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -19,6 +19,7 @@ import ( "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/providers/adfs" + "github.com/vouch/vouch-proxy/pkg/providers/azure" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/providers/github" "github.com/vouch/vouch-proxy/pkg/providers/google" @@ -69,6 +70,8 @@ func getProvider() Provider { return indieauth.Provider{} case cfg.Providers.ADFS: return adfs.Provider{} + case cfg.Providers.Azure: + return azure.Provider{} case cfg.Providers.HomeAssistant: return homeassistant.Provider{} case cfg.Providers.OpenStax: diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index c6d0f7c7..6863705c 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -37,6 +37,7 @@ var ( GitHub: "github", IndieAuth: "indieauth", ADFS: "adfs", + Azure: "azure", OIDC: "oidc", HomeAssistant: "homeassistant", OpenStax: "openstax", @@ -50,6 +51,7 @@ type OAuthProviders struct { GitHub string IndieAuth string ADFS string + Azure string OIDC string HomeAssistant string OpenStax string @@ -87,6 +89,7 @@ func oauthBasicTest() error { GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.HomeAssistant && GenOAuth.Provider != Providers.ADFS && + GenOAuth.Provider != Providers.Azure && GenOAuth.Provider != Providers.OIDC && GenOAuth.Provider != Providers.OpenStax && GenOAuth.Provider != Providers.Nextcloud { @@ -135,7 +138,7 @@ func setProviderDefaults() { setDefaultsADFS() configureOAuthClient() } else { - // IndieAuth, OIDC, OpenStax, Nextcloud + // IndieAuth, OIDC, OpenStax, Nextcloud, Azure configureOAuthClient() } } diff --git a/pkg/providers/azure/azure.go b/pkg/providers/azure/azure.go new file mode 100644 index 00000000..ef3c6c3a --- /dev/null +++ b/pkg/providers/azure/azure.go @@ -0,0 +1,82 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package azure + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/vouch/vouch-proxy/pkg/providers/common" + "github.com/vouch/vouch-proxy/pkg/structs" + "go.uber.org/zap" +) + +// Provider provider specific functions +type Provider struct{} + +var log *zap.SugaredLogger + +// Configure see main.go configure() +func (Provider) Configure() { + log = cfg.Logging.Logger +} + +// GetUserInfo provider specific call to get userinfomation +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { + _, _, err := common.PrepareTokensAndClient(r, ptokens, true) + if err != nil { + return err + } + + // For Azure AD, there is very little information in the /userinfo response. + // Since we can get everything we currently need from the access token, we are + // just going to extract user info and custom claims from there. + azureUser := structs.AzureUser{} + + tokenParts := strings.Split(ptokens.PAccessToken, ".") + if len(tokenParts) < 2 { + err = fmt.Errorf("azure GetUserInfo: invalid token received; not enough parts") + log.Error(err) + return err + } + + accessTokenBytes, err := base64.RawURLEncoding.DecodeString(tokenParts[1]) + if err != nil { + err = fmt.Errorf("azure GetUserInfo: decoding token failed: %+v", err) + log.Error(err) + return err + } + + if err = common.MapClaims(accessTokenBytes, customClaims); err != nil { + log.Error(err) + return err + } + + log.Debugf("azure GetUserInfo: getting user info from accessToken: %+v", string(accessTokenBytes)) + if err = json.Unmarshal(accessTokenBytes, &azureUser); err != nil { + err = fmt.Errorf("azure getUserInfoFromTokens: unpacking token into AzureUser failed: %+v", err) + log.Error(err) + return err + } + + azureUser.PrepareUserData() + + user.Username = azureUser.Username + user.Name = azureUser.Name + user.Email = azureUser.Email + log.Infof("azure GetUserInfo: User: %+v", user) + + return nil +} diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 2444e004..607c3dd9 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -44,6 +44,26 @@ func (u *User) PrepareUserData() { } } +// AzureUser is a retrieved and authenticated user from Azure AD +type AzureUser struct { + User + Sub string `json:"sub"` + UPN string `json:"upn"` +} + +func (u *AzureUser) PrepareUserData() { + // AzureAD uses the 'upn' (UserPrincipleName) field to store the email address of the user + // See https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-userprincipalname + + if u.Username == "" { + u.Username = u.UPN + } + + if u.Email == "" { + u.Email = u.UPN + } +} + // GoogleUser is a retrieved and authentiacted user from Google. // unused! // TODO: see if these should be pointers to the *User object as per From 67cce8abdcb01574cf79edfe048cbf3bb6f62ec1 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 10 Jul 2020 11:44:37 -0700 Subject: [PATCH 456/736] fix #290 add Azure AD --- README.md | 1 + pkg/cfg/oauth.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b6c13a6d..c53675b6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Vouch Proxy supports many OAuth login providers and can enforce authentication t - [IndieAuth](https://indieauth.spec.indieweb.org/) - [Okta](https://developer.okta.com/blog/2018/08/28/nginx-auth-request) - [ADFS](https://github.com/vouch/vouch-proxy/pull/68) +- [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) - Keycloak diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 6863705c..8bfdd6df 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -37,7 +37,7 @@ var ( GitHub: "github", IndieAuth: "indieauth", ADFS: "adfs", - Azure: "azure", + Azure: "azure", OIDC: "oidc", HomeAssistant: "homeassistant", OpenStax: "openstax", From 6e3cc77ec4a8d821dd747b8f85ec550f2865b13e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 10 Jul 2020 12:12:48 -0700 Subject: [PATCH 457/736] #290 provide example config --- config/config.yml_example_azure | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 config/config.yml_example_azure diff --git a/config/config.yml_example_azure b/config/config.yml_example_azure new file mode 100644 index 00000000..ebab962a --- /dev/null +++ b/config/config.yml_example_azure @@ -0,0 +1,25 @@ +# vouch config +# bare minimum to get vouch running with Azure AD +# https://github.com/vouch/vouch-proxy/issues/290 + +vouch: + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate to Azure AD + allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + # secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + provider: azure + client_id: 123456789 + client_secret: ******** + auth_url: https://login.microsoftonline.com/.../oauth2/v2.0/authorize + token_url: https://login.microsoftonline.com/.../oauth2/v2.0/token + scopes: + - openid + - email + - profile + callback_url: https://vouch.yourdomain/auth \ No newline at end of file From d5939fcf613b349dd5bda74fe26ec4b1bb3bd9a6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 10 Jul 2020 12:19:38 -0700 Subject: [PATCH 458/736] #266 add cookie.domain when allowAllUsers: true --- config/config.yml_example_adfs | 13 +++++++++--- config/config.yml_example_gitea | 21 +++++++++++++------- config/config.yml_example_github | 7 +++++++ config/config.yml_example_github_enterprise | 22 ++++++++++++++------- config/config.yml_example_google | 16 ++++++++++++--- config/config.yml_example_homeassistant | 12 ++++++----- config/config.yml_example_indieauth | 10 ++++++++-- config/config.yml_example_nextcloud | 6 ++++++ config/config.yml_example_oidc | 8 ++++++-- 9 files changed, 86 insertions(+), 29 deletions(-) diff --git a/config/config.yml_example_adfs b/config/config.yml_example_adfs index 7189ce67..fe12dcba 100644 --- a/config/config.yml_example_adfs +++ b/config/config.yml_example_adfs @@ -5,14 +5,21 @@ vouch: # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate to ADFS allowAllUsers: true + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + # secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + oauth: provider: adfs client_id: k8s client_secret: sauceSecret - auth_url: https://adfs.example.com/adfs/oauth2/authorize/ - token_url: https://adfs.example.com/adfs/oauth2/token/ + auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ + token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ scopes: - openid - email - profile - callback_url: https://vouch.example.com/auth \ No newline at end of file + callback_url: https://vouch.yourdomain.com/auth \ No newline at end of file diff --git a/config/config.yml_example_gitea b/config/config.yml_example_gitea index dbcae321..521bc987 100644 --- a/config/config.yml_example_gitea +++ b/config/config.yml_example_gitea @@ -4,19 +4,26 @@ vouch: domains: - - vouch.example + - yourdomain.com # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea # allowAllUsers: true + # cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + # secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + oauth: - # replace "gitea.example" with the domain your Gitea instance runs on + # replace "gitea.yourdomain.com" with the domain your Gitea instance runs on # create a new OAuth application at: - # https://gitea.example/user/settings/applications + # https://gitea.yourdomain.com/user/settings/applications provider: github client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - callback_url: https://vouch.example/auth - auth_url: https://gitea.example/login/oauth/authorize - token_url: https://gitea.example/login/oauth/access_token - user_info_url: https://gitea.example/api/v1/user?token= + auth_url: https://gitea.yourdomain.com/login/oauth/authorize + token_url: https://gitea.yourdomain.com/login/oauth/access_token + user_info_url: https://gitea.yourdomain.com/api/v1/user?token= + callback_url: https://yourdomain.com/auth diff --git a/config/config.yml_example_github b/config/config.yml_example_github index 0e7c051e..983a4686 100644 --- a/config/config.yml_example_github +++ b/config/config.yml_example_github @@ -15,6 +15,13 @@ vouch: # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at GitHub # allowAllUsers: true + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + # set teamWhitelist: to list of teams and/or GitHub organizations # When putting an organization id without a slash, it will allow all (public) members from the organization. # The client will try to read the private organization membership using the client credentials, if that's not possible diff --git a/config/config.yml_example_github_enterprise b/config/config.yml_example_github_enterprise index 384e721b..f490d738 100644 --- a/config/config.yml_example_github_enterprise +++ b/config/config.yml_example_github_enterprise @@ -8,13 +8,21 @@ vouch: # each of these domains must serve the url https://login.$domains[0] https://login.$domains[1] ... # the callback_urls will be to these domains domains: - - yoursite.com + - yourdomain.com - yourothersite.io # - OR - # instead of setting specific domains you may prefer to allow all users... # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + # set teamWhitelist: to list of teams and/or GitHub organizations # When putting an organization id without a slash, it will allow all (public) members from the organization. # The client will try to read the private organization membership using the client credentials, if that's not possible @@ -28,17 +36,17 @@ vouch: oauth: # create a new OAuth application at: - # https://githubenterprise.yoursite.com/settings/applications/new + # https://githubenterprise.yourdomain.com/settings/applications/new provider: github client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - auth_url: https://githubenterprise.yoursite.com/login/oauth/authorize - token_url: https://githubenterprise.yoursite.com/login/oauth/access_token - user_info_url: https://githubenterprise.yoursite.com/api/v3/user?access_token= + auth_url: https://githubenterprise.yourdomain.com/login/oauth/authorize + token_url: https://githubenterprise.yourdomain.com/login/oauth/access_token + user_info_url: https://githubenterprise.yourdomain.com/api/v3/user?access_token= # relevant only if teamWhitelist is configured; colon-prefixed parts are parameters that # will be replaced with the respective values. - user_team_url: https://githubenterprise.yoursite.com/api/v3/orgs/:org_id/teams/:team_slug/memberships/:username?access_token= - user_org_url: https://githubenterprise.yoursite.com/api/v3/orgs/:org_id/members/:username?access_token= + user_team_url: https://githubenterprise.yourdomain.com/api/v3/orgs/:org_id/teams/:team_slug/memberships/:username?access_token= + user_org_url: https://githubenterprise.yourdomain.com/api/v3/orgs/:org_id/members/:username?access_token= # these GitHub OAuth defaults are set for you.. # scopes: # - user diff --git a/config/config.yml_example_google b/config/config.yml_example_google index 9a93abfd..548129b4 100644 --- a/config/config.yml_example_google +++ b/config/config.yml_example_google @@ -6,7 +6,17 @@ vouch: domains: - yourdomain.com - yourotherdomain.com - + + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea + # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + oauth: provider: google # get credentials from... @@ -16,5 +26,5 @@ oauth: callback_urls: - http://yourdomain.com:9090/auth - http://yourotherdomain.com:9090/auth - preferredDomain: yourdomain.com - # endpoints set from https://godoc.org/golang.org/x/oauth2/google + preferredDomain: yourdomain.com # be careful with this option, it may conflict with chrome on Android + # endpoints are set from https://godoc.org/golang.org/x/oauth2/google diff --git a/config/config.yml_example_homeassistant b/config/config.yml_example_homeassistant index d3ed8b70..730c6de5 100644 --- a/config/config.yml_example_homeassistant +++ b/config/config.yml_example_homeassistant @@ -11,8 +11,13 @@ vouch: domains: - yourdomain.com - # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider - allowAllUsers: false + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea + # allowAllUsers: true + + # cookie: + # secure: false # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + # domain: yourdomain.com # vouch.cookie.domain must be set when enabling allowAllUsers + # whiteList - (optional) allows only the listed usernames # usernames are usually email addresses (google, most oidc providers) or login/username for github and github enterprise @@ -20,9 +25,6 @@ vouch: whiteList: - homeassistant - # Setting publicAccess: true will accept all requests, even without a cookie. - publicAccess: false - oauth: # HomeAssistant Auth # HomeAssistant typically uses a port in the url (8123 by default) and this maybe required for the auth_url and token_url diff --git a/config/config.yml_example_indieauth b/config/config.yml_example_indieauth index 52727bfc..09a7e839 100644 --- a/config/config.yml_example_indieauth +++ b/config/config.yml_example_indieauth @@ -6,12 +6,18 @@ vouch: # domains: # valid domains that the jwt cookies can be set into # the callback_urls will be to these domains - domains: - - yourdomain.com + # domains: + # - yourdomain.com # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider allowAllUsers: true + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + # Setting publicAccess: true will accept all requests, even without a cookie. publicAccess: true diff --git a/config/config.yml_example_nextcloud b/config/config.yml_example_nextcloud index 5c88f33c..cc9142c1 100644 --- a/config/config.yml_example_nextcloud +++ b/config/config.yml_example_nextcloud @@ -15,6 +15,12 @@ vouch: # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider # allowAllUsers: true + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + oauth: # This assumes usage of pretty URLs otherwise add /index.php/ # to start of URL path diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc index ce6c9ba7..066dea41 100644 --- a/config/config.yml_example_oidc +++ b/config/config.yml_example_oidc @@ -15,8 +15,12 @@ vouch: # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider # and set vouch.cookie.domain to the domain you wish to protect # allowAllUsers: true - # cookie: - # domain: yourdomain.com + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com oauth: # Generic OpenID Connect From 0fd40b3305efa355fda6c19ccfac813f05a30092 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 10 Jul 2020 14:34:24 -0700 Subject: [PATCH 459/736] #291 use an outbound proxy by setting HTTP_PROXY --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c53675b6..4df0cee4 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy serv The following Nginx config assumes.. - Nginx, `vouch.yourdomain.com` and `protectedapp.yourdomain.com` are running on the same server -- both domains are served as `https` and have valid certs (if not, change to `listen 80` and set [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L71-L72) to `false`) +- both domains are served as `https` and have valid certs (if not, change to `listen 80` and set [vouch.cookie.secure](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L71-L72) to `false`) ```{.nginxconf} server { @@ -164,6 +164,7 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) - [running on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) - [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) +- [set `HTTP_PROXY` to relay Vouch Proxy IdP requests through an outbound proxy server](https://github.com/vouch/vouch-proxy/issues/291) Please do help us to expand this list. From 04a5607f2c59bc101be02f20081ee3ac9332309f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 10 Jul 2020 14:38:17 -0700 Subject: [PATCH 460/736] fix links to examples with line number targets --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4df0cee4..ab73720c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim ## Installation and Configuration -Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L27-L29) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L68-L69) to `yourdomain.com`. +Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L23-L33) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L81-L82) to `yourdomain.com`. - `cp ./config/config.yml_example_$OAUTH_PROVIDER ./config/config.yml` - create OAuth credentials for Vouch Proxy at [google](https://console.developers.google.com/apis/credentials) or [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/), etc @@ -42,7 +42,7 @@ Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy serv The following Nginx config assumes.. - Nginx, `vouch.yourdomain.com` and `protectedapp.yourdomain.com` are running on the same server -- both domains are served as `https` and have valid certs (if not, change to `listen 80` and set [vouch.cookie.secure](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L71-L72) to `false`) +- both domains are served as `https` and have valid certs (if not, change to `listen 80` and set [vouch.cookie.secure](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L84-L85) to `false`) ```{.nginxconf} server { From dc5d4b630e58ea12d5c69dba0820802bc641b20d Mon Sep 17 00:00:00 2001 From: ipiadm Date: Wed, 15 Jul 2020 14:56:29 -0300 Subject: [PATCH 461/736] Testing repo --- pkg/jwtmanager/jwtmanager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 83eb601a..5b92426c 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -36,8 +36,8 @@ type VouchClaims struct { Username string `json:"username"` Sites []string `json:"sites"` // tempting to make this a map but the array is fewer characters in the jwt CustomClaims map[string]interface{} - PAccessToken string - PIdToken string +// PAccessToken string +// PIdToken string jwt.StandardClaims } From 9f71a2c4f24374085d28d1ca6a816923bf0eb581 Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 16 Jul 2020 23:30:04 -0400 Subject: [PATCH 462/736] Stray params are no longer errors --- handlers/login.go | 31 +++++++++++++++--------------- handlers/login_test.go | 43 +++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 4779c906..3dd98f58 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -98,7 +98,6 @@ var ( errNoURL = errors.New("no destination URL requested") errInvalidURL = errors.New("requested destination URL appears to be invalid") errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") - errLoginStrayParams = errors.New("login request included unrecognized parameters") errDangerQS = errors.New("requested destination URL has a dangerous query string") badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} reAmpSemi = regexp.MustCompile("[&;]") @@ -117,15 +116,17 @@ var ( // * All other login params are treated as non-login params // * All non-login params between the url param and the first true login param are folded into the url param // * All remaining non-login params are considered stray non-login params -// * Error is returned if the url cannot be parsed *or* it contains stray non-login params -// * For the benefit of unit-testing, if the url contains stray non-login params, it's -// returned anyway (in addition to error return) -func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { +// +// Returns +// * _, _, err: if an error occurred while parsing the URL +// * URL, false, nil: if URL is valid and contains no stray non-login params +// * URL, true, nil: if URL is valid and contains stray non-login params +func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, []string, error) { // url.URL.Query return a map and therefore makes no guarantees about param order // Therefore we have to ascertain the param order by inspecting the raw query var urlParam *url.URL = nil // Will be url.URL for the url param - strayParams := false // Will be true if stray params are found urlParamDone := false // Will be true when we're done building urlParam (but we're still checking for stray params) + strays := []string{} // List of stray params for _, param := range reAmpSemi.Split(loginURL.RawQuery, -1) { paramKeyVal := strings.Split(param, "=") @@ -142,14 +143,14 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { // Found it parsed, e := url.Parse(loginURL.Query().Get("url")) if e != nil { - return nil, e // failure to parse url param + return nil, []string{}, e // failure to parse url param } urlParam = parsed } else if !isVouchParam { // Non-vouch param before url param is a stray param log.Infof("Stray param in login request (%s)", paramKey) - strayParams = true + strays = append(strays, paramKey) } // else vouch param before url param, doesn't change outcome } else { // Looking at params after url param @@ -167,22 +168,22 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, error) { } else if !isVouchParam { // Non-vouch param after vouch param is a stray param log.Infof("Stray param in login request (%s)", paramKey) - strayParams = true + strays = append(strays, paramKey) } // else vouch param after vouch param, doesn't change outcome } } - // if there were stray parameters return an error log.Debugf("Login url param normalized to '%s'", urlParam) - if strayParams { - return urlParam, errLoginStrayParams - } - return urlParam, nil + return urlParam, strays, nil } func getValidRequestedURL(r *http.Request) (string, error) { - u, err := normalizeLoginURLParam(r.URL) + u, strays, err := normalizeLoginURLParam(r.URL) + + if len(strays) > 0 { + log.Debugf("Stray params in login url (%+q) will be ignored", strays) + } if err != nil { return "", fmt.Errorf("Not a valid login URL: %w %s", errInvalidURL, err) diff --git a/handlers/login_test.go b/handlers/login_test.go index d8a529e9..16688709 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/google/go-cmp/cmp" ) func Test_normalizeLoginURL(t *testing.T) { @@ -26,60 +27,64 @@ func Test_normalizeLoginURL(t *testing.T) { name string url string want string + wantStray []string wantErr bool }{ // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway - {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", false}, - {"extra params (blank)", "http://host/login?url=http://host/path?p2=", "http://host/path?p2=", false}, + {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", []string{}, false}, + {"extra params (blank)", "http://host/login?url=http://host/path?p2=", "http://host/path?p2=", []string{}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // Even though the p1 param is not a login param, we do not interpret is as part of the url param because it precedes it - {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", true}, + {"prior params", "http://host/login?p1=1&url=http://host/path", "http://host/path", []string{"p1"}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume vouch-* is a login param and do not fold it into url - {"vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + {"vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", []string{}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume vouch-* is a login param and do not fold it into url - {"vouch-* params before", "http://host/login?vouch-xxx=1&url=http://host/path", "http://host/path", false}, + {"vouch-* params before", "http://host/login?vouch-xxx=1&url=http://host/path", "http://host/path", []string{}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume x-vouch-* is a login param and do not fold it into url - {"x-vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", false}, + {"x-vouch-* params after", "http://host/login?url=http://host/path&vouch-xxx=2", "http://host/path", []string{}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // We assume x-vouch-* is a login param and do not fold it into url - {"x-vouch-* params before", "http://host/login?x-vouch-xxx=1&url=http://host/path", "http://host/path", false}, + {"x-vouch-* params before", "http://host/login?x-vouch-xxx=1&url=http://host/path", "http://host/path", []string{}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (vouch-*) - {"params after vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2&p3=3", "http://host/path", true}, + {"params after vouch-* params", "http://host/login?url=http://host/path&vouch-xxx=2&p3=3", "http://host/path", []string{"p3"}, false}, // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway // Even though p1 is not a login param, we do not interpret is as part of url because it follows a login param (x-vouch-*) - {"params after x-vouch-* params", "http://host/login?url=http://host/path&x-vouch-xxx=2&p3=3", "http://host/path", true}, + {"params after x-vouch-* params", "http://host/login?url=http://host/path&x-vouch-xxx=2&p3=3", "http://host/path", []string{"p3"}, false}, // This is not an RFC-compliant URL; it combines all the aspects above - {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, + {"all params", "http://host/login?p1=1&url=http://host/path?p2=2&p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", []string{"p1", "p7"}, false}, // This is an RFC-compliant URL - {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", true}, + {"all params (encoded)", "http://host/login?p1=1&url=http%3a%2f%2fhost/path%3fp2=2%26p3=3&x-vouch-xxx=4&vouch=5&error=6&p7=7", "http://host/path?p2=2&p3=3", []string{"p1", "p7"}, false}, // This is not an RFC-compliant URL; it combines all the aspects above, and it uses semicolons as parameter separators // Note that when we fold a stray param into the url param, we always do so with &s - {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", true}, + {"all params (semicolons)", "http://host/login?p1=1;url=http://host/path?p2=2;p3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2&p3=3", []string{"p1", "p5"}, false}, // This is an RFC-compliant URL that uses semicolons as parameter separators - {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", true}, + {"all params (encoded, semicolons)", "http://host/login?p1=1;url=http%3a%2f%2fhost/path%3fp2=2%3bp3=3;x-vouch-xxx=4;p5=5", "http://host/path?p2=2;p3=3", []string{"p1", "p5"}, false}, // Real world tests // since v0.4.0 the vouch README has specified an Nginx config including a 302 redirect in the following format... - {"Vouch Proxy README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", false}, - {"Vouch Proxy README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", false}, - {"Vouch Proxy README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", false}, + {"Vouch Proxy README (with error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=3&X-Vouch-Token=TOKEN&error=anerror", "http://host/path?p2=2", []string{}, false}, + {"Vouch Proxy README (blank error)", "http://host/login?url=http://host/path?p2=2&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2", []string{}, false}, + {"Vouch Proxy README (semicolons, blank error)", "http://host/login?url=http://host/path?p2=2;p3=3&vouch-failcount=&X-Vouch-Token=&error=", "http://host/path?p2=2&p3=3", []string{}, false}, // Nginx Ingress controler for Kubernetes adds the parameter `rd` to these calls // https://github.com/vouch/vouch-proxy/issues/289 - {"rd param appended by Nginx Ingress", "http://host/login?url=http://host/path?p2=2&p3=3&vouch-failcount=&X-Vouch-Token=&error=&rd=http%3a%2f%2fhost/path%3fp2=2%3bp3=3", "http://host/path?p2=2&p3=3", false}, + {"rd param appended by Nginx Ingress", "http://host/login?url=http://host/path?p2=2&p3=3&vouch-failcount=&X-Vouch-Token=&error=&rd=http%3a%2f%2fhost/path%3fp2=2%3bp3=3", "http://host/path?p2=2&p3=3", []string{}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { u, _ := url.Parse(tt.url) - got, err := normalizeLoginURLParam(u) + got, stray, err := normalizeLoginURLParam(u) if got.String() != tt.want { t.Errorf("normalizeLoginURLParam() = %v, want %v", got, tt.want) } + if !cmp.Equal(stray, tt.wantStray) { + t.Errorf("normalizeLoginURLParam() stray params incorrectly parsed, got %+q, expected %+q", stray, tt.wantStray) + } if (err != nil) != tt.wantErr { t.Errorf("normalizeLoginURLParam() err = %v", err) - } + } }) } } From e33be274b88bf95be55dcac17a12906228798ccf Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 16 Jul 2020 23:37:04 -0400 Subject: [PATCH 463/736] No longer need to special-case rd stray param --- handlers/login.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 3dd98f58..37c04417 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -134,8 +134,7 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, []string, error) { lcParamKey := strings.ToLower(paramKey) isVouchParam := strings.HasPrefix(lcParamKey, cfg.Branding.LCName) || strings.HasPrefix(lcParamKey, "x-"+cfg.Branding.LCName) || - paramKey == "error" || - paramKey == "rd" + paramKey == "error" if urlParam == nil { // Still looking for url param From db320697bb98de25f7e2425dff78d4caa5e13f9a Mon Sep 17 00:00:00 2001 From: ipiadm Date: Wed, 22 Jul 2020 21:46:44 -0300 Subject: [PATCH 464/736] Do not collect IdP tokens unless configured to do so --- .defaults.yml | 5 +++-- pkg/jwtmanager/jwtmanager.go | 13 +++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index 54e2f3bb..5355712d 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -42,8 +42,9 @@ vouch: redirect: X-Vouch-Requested-URI # claims: claimheader: X-Vouch-IdP-Claims- - accesstoken: X-Vouch-IdP-AccessToken - idtoken: X-Vouch-IdP-IdToken + # https://github.com/vouch/vouch-proxy/issues/287 + # accesstoken: X-Vouch-IdP-AccessToken + # idtoken: X-Vouch-IdP-IdToken # test_url: # post_logout_redirect_uris: # oauth: diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 5b92426c..bd761eb8 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -36,8 +36,8 @@ type VouchClaims struct { Username string `json:"username"` Sites []string `json:"sites"` // tempting to make this a map but the array is fewer characters in the jwt CustomClaims map[string]interface{} -// PAccessToken string -// PIdToken string + PAccessToken string + PIdToken string jwt.StandardClaims } @@ -86,6 +86,15 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt StandardClaims, } + // https://github.com/vouch/vouch-proxy/issues/287 + if cfg.Cfg.Headers.AccessToken == "" { + claims.PAccessToken = "" + } + + if cfg.Cfg.Headers.IDToken == "" { + claims.PIdToken = "" + } + claims.StandardClaims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix() // https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims From 5f96c0e017fb6716ed0af9dc6aeb30d4ba1b555d Mon Sep 17 00:00:00 2001 From: Ben Artin Date: Thu, 23 Jul 2020 21:36:47 -0400 Subject: [PATCH 465/736] =?UTF-8?q?Don=E2=80=99t=20treat=20rd=20as=20a=20s?= =?UTF-8?q?tray=20login=20param?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handlers/login.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handlers/login.go b/handlers/login.go index 37c04417..6a60c8df 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -134,7 +134,8 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, []string, error) { lcParamKey := strings.ToLower(paramKey) isVouchParam := strings.HasPrefix(lcParamKey, cfg.Branding.LCName) || strings.HasPrefix(lcParamKey, "x-"+cfg.Branding.LCName) || - paramKey == "error" + paramKey == "error" || // Used by VouchProxy login + paramKey == "rd" // Passed to VouchProxy by nginx-ingress and then ignored (see #289) if urlParam == nil { // Still looking for url param From 0c8f05dd402fe0e8c48ff3fc640bf74c2116e69d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 30 Jul 2020 10:17:54 -0700 Subject: [PATCH 466/736] add gosec --- do.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/do.sh b/do.sh index a4e3e44e..2137db2c 100755 --- a/do.sh +++ b/do.sh @@ -308,11 +308,16 @@ profile() { go tool pprof -http=0.0.0.0:19091 http://0.0.0.0:9090/debug/pprof/profile?seconds=10 } + gofmt() { # segfault's without exec since it would just call this function infinitely :) exec gofmt -w -s . } +gosec() { + # segfault's without exec since it would just call this function infinitely :) + exec gosec ./... +} usage() { cat < Date: Thu, 30 Jul 2020 10:18:20 -0700 Subject: [PATCH 467/736] minor edits for clarity --- config/config.yml_example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index aa726fbd..95d7e5fb 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -1,6 +1,6 @@ # vouch config -# you should probably start with one of the other configs in the example directory +# you should probably start with one of the other example configs in this directory # Vouch Proxy does a fairly good job of setting its config to sane defaults # be aware of the yaml indentation, the only top level elements are `vouch` and `oauth`. @@ -36,7 +36,7 @@ vouch: # allowAllUsers: false # vouch.cookie.domain must be set below when enabling allowAllUsers - # Setting publicAccess: true will accept all requests, even without a cookie. - VOUCH_PUBLICACCESS + # Setting publicAccess: true will accept all requests, even without a valid jwt/cookie. - VOUCH_PUBLICACCESS # If the user is logged in, the cookie will be validated and the user header will be set. # You will need to direct people to the Vouch Proxy login page from your application. # publicAccess: false From 52e01582bd11a1c6440f4ff086fbd00b76334ceb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 30 Jul 2020 10:32:24 -0700 Subject: [PATCH 468/736] #296 fmt, clarify return of strays --- handlers/login.go | 18 +++++++++--------- handlers/login_test.go | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 6a60c8df..038f4ebc 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -95,12 +95,12 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { } var ( - errNoURL = errors.New("no destination URL requested") - errInvalidURL = errors.New("requested destination URL appears to be invalid") - errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") - errDangerQS = errors.New("requested destination URL has a dangerous query string") - badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} - reAmpSemi = regexp.MustCompile("[&;]") + errNoURL = errors.New("no destination URL requested") + errInvalidURL = errors.New("requested destination URL appears to be invalid") + errURLNotHTTP = errors.New("requested destination URL is not a valid URL (does not begin with 'http://' or 'https://')") + errDangerQS = errors.New("requested destination URL has a dangerous query string") + badStrings = []string{"http://", "https://", "data:", "ftp://", "ftps://", "//", "javascript:"} + reAmpSemi = regexp.MustCompile("[&;]") ) // inspect login query params to located the url param, while taking into account that the login URL may be @@ -116,11 +116,11 @@ var ( // * All other login params are treated as non-login params // * All non-login params between the url param and the first true login param are folded into the url param // * All remaining non-login params are considered stray non-login params -// +// // Returns // * _, _, err: if an error occurred while parsing the URL -// * URL, false, nil: if URL is valid and contains no stray non-login params -// * URL, true, nil: if URL is valid and contains stray non-login params +// * URL, empty array, nil: if URL is valid and contains no stray non-login params +// * URL, array of stray params, nil: if URL is valid and contains stray non-login params func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, []string, error) { // url.URL.Query return a map and therefore makes no guarantees about param order // Therefore we have to ascertain the param order by inspecting the raw query diff --git a/handlers/login_test.go b/handlers/login_test.go index 16688709..14f5270a 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -16,19 +16,19 @@ import ( "net/url" "testing" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/vouch/vouch-proxy/pkg/cfg" - "github.com/google/go-cmp/cmp" ) func Test_normalizeLoginURL(t *testing.T) { setUp("/config/testing/handler_login_url.yml") tests := []struct { - name string - url string - want string + name string + url string + want string wantStray []string - wantErr bool + wantErr bool }{ // This is not an RFC-compliant URL because it does not encode :// in the url param; we accept it anyway {"extra params", "http://host/login?url=http://host/path?p2=2", "http://host/path?p2=2", []string{}, false}, @@ -84,7 +84,7 @@ func Test_normalizeLoginURL(t *testing.T) { } if (err != nil) != tt.wantErr { t.Errorf("normalizeLoginURLParam() err = %v", err) - } + } }) } } From 250e269149cd911b91c9c3443b57baa3b4464ebc Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 30 Jul 2020 10:59:41 -0700 Subject: [PATCH 469/736] use a package type'd context key --- pkg/cfg/cfg.go | 8 ++++++-- pkg/jwtmanager/jwtcache.go | 4 +++- pkg/responses/responses.go | 2 +- pkg/structs/structs.go | 1 + 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 364d7fe7..3e8def28 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -130,11 +130,15 @@ const ( minBase64Length = 44 base64Bytes = 32 - // ErrCtx set or check the http request context to see if it has errored + // ErrCtxKey set or check the http request context to see if it has errored // see `responses.Error401` and `jwtmanager.JWTCacheHandler` for example - ErrCtx = "isErr" + ErrCtxKey ctxKey = 0 ) +// use a typed ctxKey to avoid context key collission +// https://blog.golang.org/context#TOC_3.2. +type ctxKey int + // Configure called at the very top of main() // the order of config follows the Viper conventions... // diff --git a/pkg/jwtmanager/jwtcache.go b/pkg/jwtmanager/jwtcache.go index 9ff85bfb..5a04b49b 100644 --- a/pkg/jwtmanager/jwtcache.go +++ b/pkg/jwtmanager/jwtcache.go @@ -77,7 +77,9 @@ func JWTCacheHandler(next http.Handler) http.Handler { next.ServeHTTP(w, r) if jwt != "" && - r.Context().Err() == nil { // r.Context().Done() is still open + r.Context().Err() == nil { + // see responses.addErrandCancelRequest() + // r.Context().Done() is still open // cache the response headers for this jwt // log.Debug("setting cache for %+v", w.Header().Clone()) Cache.SetDefault(jwt, w.Header().Clone()) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 7c823f4f..f3f6d6de 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -117,7 +117,7 @@ func Error403(w http.ResponseWriter, r *http.Request, e error) { // cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler` func addErrandCancelRequest(r *http.Request) { ctx, cancel := context.WithCancel(r.Context()) - ctx = context.WithValue(ctx, cfg.ErrCtx, true) + ctx = context.WithValue(ctx, cfg.ErrCtxKey, true) *r = *r.Clone(ctx) cancel() // we're done return diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 607c3dd9..e42c0d60 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -51,6 +51,7 @@ type AzureUser struct { UPN string `json:"upn"` } +// PrepareUserData implement PersonalData interface func (u *AzureUser) PrepareUserData() { // AzureAD uses the 'upn' (UserPrincipleName) field to store the email address of the user // See https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-userprincipalname From 8c46f0f161527829e564d85aadb960ed56c73e98 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 30 Jul 2020 12:27:15 -0700 Subject: [PATCH 470/736] #298 test presence and absence of tokens --- .../jwtmanager_has_idp_token_claims.yml | 31 ++++++++ handlers/handlers_test.go | 78 +++++++++++++++++-- 2 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 config/testing/jwtmanager_has_idp_token_claims.yml diff --git a/config/testing/jwtmanager_has_idp_token_claims.yml b/config/testing/jwtmanager_has_idp_token_claims.yml new file mode 100644 index 00000000..ed0e0e31 --- /dev/null +++ b/config/testing/jwtmanager_has_idp_token_claims.yml @@ -0,0 +1,31 @@ +vouch: + testing: true + logLevel: debug + listen: 0.0.0.0 + port: 9090 + + allowAllUsers: true + + headers: + claims: + - groups + - boolean_claim + - family_name + - http://www.example.com/favorite_color + accesstoken: X-Vouch-IdP-AccessToken + idtoken: X-Vouch-IdP-IdToken + + cookie: + name: vouchTestingCookie + + session: + name: VouchTestingSession + + jwt: + secret: testing + +oauth: + provider: indieauth + client_id: http://vouch.github.io + auth_url: https://indielogin.com/auth + callback_url: http://vouch.github.io:9090/auth diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 209d520e..6a968940 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package handlers import ( + "encoding/json" "os" "path/filepath" "testing" @@ -30,17 +31,12 @@ var ( token = &oauth2.Token{AccessToken: "123"} ) +// setUp load config file and then call Configure() for dependent packages func setUp(configFile string) { os.Setenv("VOUCH_CONFIG", filepath.Join(os.Getenv("VOUCH_ROOT"), configFile)) cfg.InitForTestPurposes() - // cfg.Cfg.AllowAllUsers = false - // cfg.Cfg.WhiteList = make([]string, 0) - // cfg.Cfg.TeamWhiteList = make([]string, 0) - // cfg.Cfg.Domains = []string{"domain1"} - Configure() - domains.Configure() jwtmanager.Configure() cookie.Configure() @@ -115,3 +111,73 @@ func TestVerifyUserNegative(t *testing.T) { assert.False(t, ok) assert.NotNil(t, err) } + +// copied from jwtmanager_test.go +// it should live there but circular imports are resolved if it lives here +var ( + u1 = structs.User{ + Username: "test@testing.com", + Name: "Test Name", + } + t1 = structs.PTokens{ + PAccessToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRvaXU4In0.eyJzdWIiOiJuZnlmZSIsImF1ZCI6ImltX29pY19jbGllbnQiLCJqdGkiOiJUOU4xUklkRkVzUE45enU3ZWw2eng2IiwiaXNzIjoiaHR0cHM6XC9cL3Nzby5tZXljbG91ZC5uZXQ6OTAzMSIsImlhdCI6MTM5MzczNzA3MSwiZXhwIjoxMzkzNzM3MzcxLCJub25jZSI6ImNiYTU2NjY2LTRiMTItNDU2YS04NDA3LTNkMzAyM2ZhMTAwMiIsImF0X2hhc2giOiJrdHFvZVBhc2praVY5b2Z0X3o5NnJBIn0.g1Jc9DohWFfFG3ppWfvW16ib6YBaONC5VMs8J61i5j5QLieY-mBEeVi1D3vr5IFWCfivY4hZcHtoJHgZk1qCumkAMDymsLGX-IGA7yFU8LOjUdR4IlCPlZxZ_vhqr_0gQ9pCFKDkiOv1LVv5x3YgAdhHhpZhxK6rWxojg2RddzvZ9Xi5u2V1UZ0jukwyG2d4PRzDn7WoRNDGwYOEt4qY7lv_NO2TY2eAklP-xYBWu0b9FBElapnstqbZgAXdndNs-Wqp4gyQG5D0owLzxPErR9MnpQfgNcai-PlWI_UrvoopKNbX0ai2zfkuQ-qh6Xn8zgkiaYDHzq4gzwRfwazaqA", + PIdToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRvaXU4In0.eyJzdWIiOiJuZnlmZSIsImF1ZCI6ImltX29pY19jbGllbnQiLCJqdGkiOiJUOU4xUklkRkVzUE45enU3ZWw2eng2IiwiaXNzIjoiaHR0cHM6XC9cL3Nzby5tZXljbG91ZC5uZXQ6OTAzMSIsImlhdCI6MTM5MzczNzA3MSwiZXhwIjoxMzkzNzM3MzcxLCJub25jZSI6ImNiYTU2NjY2LTRiMTItNDU2YS04NDA3LTNkMzAyM2ZhMTAwMiIsImF0X2hhc2giOiJrdHFvZVBhc2praVY5b2Z0X3o5NnJBIn0.g1Jc9DohWFfFG3ppWfvW16ib6YBaONC5VMs8J61i5j5QLieY-mBEeVi1D3vr5IFWCfivY4hZcHtoJHgZk1qCumkAMDymsLGX-IGA7yFU8LOjUdR4IlCPlZxZ_vhqr_0gQ9pCFKDkiOv1LVv5x3YgAdhHhpZhxK6rWxojg2RddzvZ9Xi5u2V1UZ0jukwyG2d4PRzDn7WoRNDGwYOEt4qY7lv_NO2TY2eAklP-xYBWu0b9FBElapnstqbZgAXdndNs-Wqp4gyQG5D0owLzxPErR9MnpQfgNcai-PlWI_UrvoopKNbX0ai2zfkuQ-qh6Xn8zgkiaYDHzq4gzwRfwazaqA", + } + + lc jwtmanager.VouchClaims + + claimjson = `{ + "sub": "f:a95afe53-60ba-4ac6-af15-fab870e72f3d:mrtester", + "groups": ["Website Users", "Test Group"], + "given_name": "Mister", + "family_name": "Tester", + "email": "mrtester@test.int" + }` + customClaims = structs.CustomClaims{} +) + +// copied from jwtmanager_test.go +func init() { + // log.SetLevel(log.DebugLevel) + + lc = jwtmanager.VouchClaims{ + u1.Username, + jwtmanager.Sites, + customClaims.Claims, + t1.PAccessToken, + t1.PIdToken, + jwtmanager.StandardClaims, + } + json.Unmarshal([]byte(claimjson), &customClaims.Claims) +} + +func TestParsedIdPTokens(t *testing.T) { + tests := []struct { + name string + configFile string + wantIDPTokens bool + }{ + {"no IdP tokens", "/config/testing/handler_claims.yml", false}, + {"wants IdP tokens", "/config/testing/jwtmanager_has_idp_token_claims.yml", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setUp(tt.configFile) + uts := jwtmanager.CreateUserTokenString(u1, customClaims, t1) + utsParsed, _ := jwtmanager.ParseTokenString(uts) + utsPtokens, _ := jwtmanager.PTokenClaims(utsParsed) + + if tt.wantIDPTokens { + if t1.PIdToken != utsPtokens.PIdToken || t1.PAccessToken != utsPtokens.PAccessToken { + t.Errorf("got PIdToken = %s, PAccessToken = %s, \nwant %s , %s", utsPtokens.PIdToken, utsPtokens.PAccessToken, t1.PIdToken, t1.PAccessToken) + } + } else { + if utsPtokens.PIdToken != "" || utsPtokens.PAccessToken != "" { + t.Errorf("PIdToken and PAccessToken = should be '' got '%s', '%s'", utsPtokens.PIdToken, utsPtokens.PAccessToken) + } + } + }) + } + +} From 7f2d675241d14fe6e60749ee16dab44f89af6a2c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 30 Jul 2020 12:56:14 -0700 Subject: [PATCH 471/736] Proxy for Google Cloud Run Services example --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ab73720c..bf54abdc 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [running on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) - [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) - [set `HTTP_PROXY` to relay Vouch Proxy IdP requests through an outbound proxy server](https://github.com/vouch/vouch-proxy/issues/291) +- [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) Please do help us to expand this list. From 0f889c46c12fd6b920ecf67ae711a5a65a7d5b80 Mon Sep 17 00:00:00 2001 From: Hussein Srour Date: Sun, 9 Aug 2020 13:11:28 +0300 Subject: [PATCH 472/736] added S256 code_challenge support --- config/config.yml_example_oidc | 1 + handlers/auth.go | 17 +++++++-- handlers/handlers.go | 3 +- handlers/login.go | 37 ++++++++++++++++++-- pkg/cfg/oauth.go | 1 + pkg/providers/adfs/adfs.go | 3 +- pkg/providers/azure/azure.go | 5 +-- pkg/providers/common/common.go | 4 +-- pkg/providers/github/github.go | 4 +-- pkg/providers/google/google.go | 5 +-- pkg/providers/homeassistant/homeassistant.go | 5 +-- pkg/providers/indieauth/indieauth.go | 3 +- pkg/providers/nextcloud/nextcloud.go | 3 +- pkg/providers/openid/openid.go | 5 +-- pkg/providers/openstax/openstax.go | 5 +-- 15 files changed, 78 insertions(+), 23 deletions(-) diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc index 066dea41..41e134bc 100644 --- a/config/config.yml_example_oidc +++ b/config/config.yml_example_oidc @@ -31,6 +31,7 @@ oauth: auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize token_url: https://{yourOktaDomain}/oauth2/default/v1/token user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo + code_challenge_method: S256 scopes: - openid - email diff --git a/handlers/auth.go b/handlers/auth.go index 72668828..48668d50 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -13,6 +13,7 @@ package handlers import ( "errors" "fmt" + "golang.org/x/oauth2" "net/http" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -61,7 +62,17 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { customClaims := structs.CustomClaims{} ptokens := structs.PTokens{} - if err := getUserInfo(r, &user, &customClaims, &ptokens); err != nil { + // is code challenge enabled? + authCodeOptions := []oauth2.AuthCodeOption{} + + if cfg.GenOAuth.CodeChallengeMethod != "" { + authCodeOptions = []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("code_challenge", session.Values["codeChallenge"].(string)), + oauth2.SetAuthURLParam("code_verifier", session.Values["codeVerifier"].(string)), + } + } + + if err := getUserInfo(r, &user, &customClaims, &ptokens, authCodeOptions...); err != nil { responses.Error400(w, r, fmt.Errorf("/auth Error while retreiving user info after successful login at the OAuth provider: %w", err)) return } @@ -149,6 +160,6 @@ func verifyUser(u interface{}) (bool, error) { } } -func getUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) error { - return provider.GetUserInfo(r, user, customClaims, ptokens) +func getUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) error { + return provider.GetUserInfo(r, user, customClaims, ptokens, opts...) } diff --git a/handlers/handlers.go b/handlers/handlers.go index 2957bfef..608aaeec 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package handlers import ( + "golang.org/x/oauth2" "net/http" "github.com/gorilla/sessions" @@ -34,7 +35,7 @@ import ( // Provider each Provider must support GetuserInfo type Provider interface { Configure() - GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) error + GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) error } const ( diff --git a/handlers/login.go b/handlers/login.go index 038f4ebc..4ce43789 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -13,11 +13,13 @@ package handlers import ( "errors" "fmt" + "github.com/gorilla/sessions" "net/http" "net/url" "regexp" "strings" + cv "github.com/nirasan/go-oauth-pkce-code-verifier" "github.com/theckman/go-securerandom" "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" @@ -76,6 +78,12 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { failcount++ session.Values[requestedURL] = failcount + // Add code challenge if enabled + if cfg.GenOAuth.CodeChallengeMethod != "" { + log.Debugf("Adding code challenge") + appendCodeChallenge(*session) + } + log.Debugf("saving session with failcount %d", failcount) if err = session.Save(r, w); err != nil { log.Error(err) @@ -89,7 +97,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // SUCCESS // bounce to oauth provider for login - var oURL = oauthLoginURL(r, state) + var oURL = oauthLoginURL(*session, r, state) log.Debugf("redirecting to oauthURL %s", oURL) responses.Redirect302(w, r, oURL) } @@ -226,7 +234,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { return u.String(), nil } -func oauthLoginURL(r *http.Request, state string) string { +func oauthLoginURL(session sessions.Session, r *http.Request, state string) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var lurl string @@ -260,6 +268,11 @@ func oauthLoginURL(r *http.Request, state string) string { } else { lurl = cfg.OAuthClient.AuthCodeURL(state) } + + // append code challenge and code challenge method query parameters if enabled + if cfg.GenOAuth.CodeChallengeMethod != "" { + lurl = fmt.Sprintf("%s&code_challenge_method=%s&code_challenge=%s", lurl, cfg.GenOAuth.CodeChallengeMethod, session.Values["codeChallenge"].(string)) + } } // log.Debugf("loginURL %s", url) return lurl @@ -275,3 +288,23 @@ func generateStateNonce() (string, error) { state = regExJustAlphaNum.ReplaceAllString(state, "") return state, nil } + +func appendCodeChallenge(session sessions.Session) { + var codeChallenge string + var CodeVerifier, _ = cv.CreateCodeVerifier() + switch strings.ToUpper(cfg.GenOAuth.CodeChallengeMethod) { + case "S256": + codeChallenge = CodeVerifier.CodeChallengeS256() + break + case "PLAIN": + codeChallenge = CodeVerifier.CodeChallengePlain() + // TODO support plain text code challenge + log.Fatal("plain code challenge method is not supported") + return + default: + log.Fatal("Code challenge method %s is invalid", cfg.GenOAuth.CodeChallengeMethod) + return + } + session.Values["codeChallenge"] = codeChallenge + session.Values["codeVerifier"] = CodeVerifier.Value +} diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 8bfdd6df..2e5425de 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -75,6 +75,7 @@ type oauthConfig struct { UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` PreferredDomain string `mapstructure:"preferredDomain"` + CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` } func configureOauth() error { diff --git a/pkg/providers/adfs/adfs.go b/pkg/providers/adfs/adfs.go index a5bd512c..1c55253f 100644 --- a/pkg/providers/adfs/adfs.go +++ b/pkg/providers/adfs/adfs.go @@ -14,6 +14,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "golang.org/x/oauth2" "io/ioutil" "net/http" "net/url" @@ -46,7 +47,7 @@ func (Provider) Configure() { // GetUserInfo provider specific call to get userinfomation // More info: https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-scenarios-for-developers#supported-scenarios -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { code := r.URL.Query().Get("code") log.Debugf("code: %s", code) diff --git a/pkg/providers/azure/azure.go b/pkg/providers/azure/azure.go index ef3c6c3a..edf44ed9 100644 --- a/pkg/providers/azure/azure.go +++ b/pkg/providers/azure/azure.go @@ -14,6 +14,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "golang.org/x/oauth2" "net/http" "strings" @@ -34,8 +35,8 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { - _, _, err := common.PrepareTokensAndClient(r, ptokens, true) +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + _, _, err := common.PrepareTokensAndClient(r, ptokens, true, opts...) if err != nil { return err } diff --git a/pkg/providers/common/common.go b/pkg/providers/common/common.go index db71528a..461b1d84 100644 --- a/pkg/providers/common/common.go +++ b/pkg/providers/common/common.go @@ -30,8 +30,8 @@ func Configure() { } // PrepareTokensAndClient setup the client, usually for a UserInfo request -func PrepareTokensAndClient(r *http.Request, ptokens *structs.PTokens, setProviderToken bool) (*http.Client, *oauth2.Token, error) { - providerToken, err := cfg.OAuthClient.Exchange(context.TODO(), r.URL.Query().Get("code")) +func PrepareTokensAndClient(r *http.Request, ptokens *structs.PTokens, setProviderToken bool, opts ...oauth2.AuthCodeOption) (*http.Client, *oauth2.Token, error) { + providerToken, err := cfg.OAuthClient.Exchange(context.TODO(), r.URL.Query().Get("code"), opts...) if err != nil { return nil, nil, err } diff --git a/pkg/providers/github/github.go b/pkg/providers/github/github.go index 15f5cee5..018806ef 100644 --- a/pkg/providers/github/github.go +++ b/pkg/providers/github/github.go @@ -26,7 +26,7 @@ import ( // Provider provider specific functions type Provider struct { - PrepareTokensAndClient func(*http.Request, *structs.PTokens, bool) (*http.Client, *oauth2.Token, error) + PrepareTokensAndClient func(r *http.Request, ptokens *structs.PTokens, setProviderToken bool, opts ...oauth2.AuthCodeOption) (*http.Client, *oauth2.Token, error) } var log *zap.SugaredLogger @@ -38,7 +38,7 @@ func (Provider) Configure() { // GetUserInfo github user info, calls github api for org and teams // https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ -func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { +func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { client, ptoken, err := me.PrepareTokensAndClient(r, ptokens, true) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/pkg/providers/google/google.go b/pkg/providers/google/google.go index 2f86e4d3..dbfa0b01 100644 --- a/pkg/providers/google/google.go +++ b/pkg/providers/google/google.go @@ -12,6 +12,7 @@ package google import ( "encoding/json" + "golang.org/x/oauth2" "io/ioutil" "net/http" @@ -32,8 +33,8 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { - client, _, err := common.PrepareTokensAndClient(r, ptokens, true) +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + client, _, err := common.PrepareTokensAndClient(r, ptokens, true, opts...) if err != nil { return err } diff --git a/pkg/providers/homeassistant/homeassistant.go b/pkg/providers/homeassistant/homeassistant.go index 8655904c..c2b7ad0b 100644 --- a/pkg/providers/homeassistant/homeassistant.go +++ b/pkg/providers/homeassistant/homeassistant.go @@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package homeassistant import ( + "golang.org/x/oauth2" "net/http" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -31,8 +32,8 @@ func (Provider) Configure() { // GetUserInfo provider specific call to get userinfomation // More info: https://developers.home-assistant.io/docs/en/auth_api.html -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { - _, providerToken, err := common.PrepareTokensAndClient(r, ptokens, false) +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + _, providerToken, err := common.PrepareTokensAndClient(r, ptokens, false, opts...) if err != nil { return err } diff --git a/pkg/providers/indieauth/indieauth.go b/pkg/providers/indieauth/indieauth.go index f1602fa1..d602fcf3 100644 --- a/pkg/providers/indieauth/indieauth.go +++ b/pkg/providers/indieauth/indieauth.go @@ -13,6 +13,7 @@ package indieauth import ( "bytes" "encoding/json" + "golang.org/x/oauth2" "io/ioutil" "mime/multipart" "net/http" @@ -34,7 +35,7 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { // indieauth sends the "me" setting in json back to the callback, so just pluck it from the callback code := r.URL.Query().Get("code") log.Errorf("ptoken.AccessToken: %s", code) diff --git a/pkg/providers/nextcloud/nextcloud.go b/pkg/providers/nextcloud/nextcloud.go index 1c8826d3..c6979798 100644 --- a/pkg/providers/nextcloud/nextcloud.go +++ b/pkg/providers/nextcloud/nextcloud.go @@ -12,6 +12,7 @@ package nextcloud import ( "encoding/json" + "golang.org/x/oauth2" "io/ioutil" "net/http" @@ -32,7 +33,7 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { client, _, err := common.PrepareTokensAndClient(r, ptokens, true) if err != nil { return err diff --git a/pkg/providers/openid/openid.go b/pkg/providers/openid/openid.go index 7bdc6319..bdc6bb7f 100644 --- a/pkg/providers/openid/openid.go +++ b/pkg/providers/openid/openid.go @@ -12,6 +12,7 @@ package openid import ( "encoding/json" + "golang.org/x/oauth2" "io/ioutil" "net/http" @@ -32,8 +33,8 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { - client, _, err := common.PrepareTokensAndClient(r, ptokens, true) +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + client, _, err := common.PrepareTokensAndClient(r, ptokens, true, opts...) if err != nil { return err } diff --git a/pkg/providers/openstax/openstax.go b/pkg/providers/openstax/openstax.go index 6e877f60..b9ccf24d 100644 --- a/pkg/providers/openstax/openstax.go +++ b/pkg/providers/openstax/openstax.go @@ -12,6 +12,7 @@ package openstax import ( "encoding/json" + "golang.org/x/oauth2" "io/ioutil" "net/http" @@ -32,8 +33,8 @@ func (Provider) Configure() { } // GetUserInfo provider specific call to get userinfomation -func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens) (rerr error) { - client, _, err := common.PrepareTokensAndClient(r, ptokens, false) +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + client, _, err := common.PrepareTokensAndClient(r, ptokens, false, opts...) if err != nil { return err } From 5c12b93b727c129732ffa30b01f08252401101e2 Mon Sep 17 00:00:00 2001 From: Hussein Srour Date: Sun, 9 Aug 2020 13:32:13 +0300 Subject: [PATCH 473/736] github test --- pkg/providers/github/github_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/providers/github/github_test.go b/pkg/providers/github/github_test.go index 4f01313e..1caf5abc 100644 --- a/pkg/providers/github/github_test.go +++ b/pkg/providers/github/github_test.go @@ -185,7 +185,7 @@ func TestGetUserInfo(t *testing.T) { mockResponse(regexMatcher(".*teams.*"), http.StatusOK, map[string]string{}, []byte("{\"state\": \"active\"}")) mockResponse(regexMatcher(".*members.*"), http.StatusNoContent, map[string]string{}, []byte("")) - provider := Provider{PrepareTokensAndClient: func(_ *http.Request, _ *structs.PTokens, _ bool) (*http.Client, *oauth2.Token, error) { + provider := Provider{PrepareTokensAndClient: func(_ *http.Request, _ *structs.PTokens, _ bool, opts ...oauth2.AuthCodeOption) (*http.Client, *oauth2.Token, error) { return client, token, nil }} err := provider.GetUserInfo(nil, user, &structs.CustomClaims{}, &structs.PTokens{}) From f222fcbab200116bdf6a7328982c3bd0836c9126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=AAn=20To=C3=A1n?= Date: Wed, 12 Aug 2020 17:37:07 +0700 Subject: [PATCH 474/736] update docker run example (#311) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bf54abdc..372291d1 100644 --- a/README.md +++ b/README.md @@ -185,11 +185,11 @@ or docker run -d \ -p 9090:9090 \ --name vouch-proxy \ - -e VOUCH_DOMAINS=yourdomain.com - -e OAUTH_PROVIDER=google - -e OAUTH_CLIENT_ID=1234 - -e OAUTH_CLIENT_SECRET=secretsecret - -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth + -e VOUCH_DOMAINS=yourdomain.com \ + -e OAUTH_PROVIDER=google \ + -e OAUTH_CLIENT_ID=1234 \ + -e OAUTH_CLIENT_SECRET=secretsecret \ + -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \ voucher/vouch-proxy ``` From 403122f2e95f033246bb1ebbec06f629d4143661 Mon Sep 17 00:00:00 2001 From: Hussein Srour Date: Thu, 13 Aug 2020 08:28:26 +0300 Subject: [PATCH 475/736] code refact --- config/config.yml_example | 3 +++ config/config.yml_example_oidc | 1 - handlers/login.go | 6 +++--- pkg/cfg/oauth.go | 28 ++++++++++++++-------------- pkg/jwtmanager/jwtmanager.go | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index 95d7e5fb..ca91279c 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -229,6 +229,9 @@ oauth: - email - profile callback_url: http://vouch.yourdomain.com:9090/auth + # PKCE method if enabled, S256 is currently supported (check https://www.oauth.com/oauth2-servers/pkce/) + # resolves issue https://github.com/vouch/vouch-proxy/issues/303 + code_challenge_method: S256 # IndieAuth # https://indielogin.com/api diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc index 41e134bc..066dea41 100644 --- a/config/config.yml_example_oidc +++ b/config/config.yml_example_oidc @@ -31,7 +31,6 @@ oauth: auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize token_url: https://{yourOktaDomain}/oauth2/default/v1/token user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo - code_challenge_method: S256 scopes: - openid - email diff --git a/handlers/login.go b/handlers/login.go index 4ce43789..13026b1b 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -97,7 +97,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // SUCCESS // bounce to oauth provider for login - var oURL = oauthLoginURL(*session, r, state) + var oURL = oauthLoginURL(r, *session) log.Debugf("redirecting to oauthURL %s", oURL) responses.Redirect302(w, r, oURL) } @@ -234,11 +234,11 @@ func getValidRequestedURL(r *http.Request) (string, error) { return u.String(), nil } -func oauthLoginURL(session sessions.Session, r *http.Request, state string) string { +func oauthLoginURL(r *http.Request, session sessions.Session) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 var lurl string - + var state string = session.Values["state"].(string) if cfg.GenOAuth.Provider == cfg.Providers.IndieAuth { lurl = cfg.OAuthClient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) } else if cfg.GenOAuth.Provider == cfg.Providers.ADFS { diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 2e5425de..7037354b 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -62,20 +62,20 @@ type OAuthProviders struct { // `envconfig` tag is for env var support // https://github.com/kelseyhightower/envconfig type oauthConfig struct { - Provider string `mapstructure:"provider"` - ClientID string `mapstructure:"client_id" envconfig:"client_id"` - ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` - AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` - TokenURL string `mapstructure:"token_url" envconfig:"token_url"` - LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` - RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` - RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` - Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` - UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` - UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` - PreferredDomain string `mapstructure:"preferredDomain"` - CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` + Provider string `mapstructure:"provider"` + ClientID string `mapstructure:"client_id" envconfig:"client_id"` + ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` + AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` + TokenURL string `mapstructure:"token_url" envconfig:"token_url"` + LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` + RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` + RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` + Scopes []string `mapstructure:"scopes"` + UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` + UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` + UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` + PreferredDomain string `mapstructure:"preferredDomain"` + CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` } func configureOauth() error { diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index bd761eb8..e7d7fd7b 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -89,7 +89,7 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt // https://github.com/vouch/vouch-proxy/issues/287 if cfg.Cfg.Headers.AccessToken == "" { claims.PAccessToken = "" - } + } if cfg.Cfg.Headers.IDToken == "" { claims.PIdToken = "" From 568577c64c8ea7de7f904bd8720588ccc51ce206 Mon Sep 17 00:00:00 2001 From: Simon Gottschlag Date: Mon, 5 Oct 2020 21:43:15 +0200 Subject: [PATCH 476/736] Make azure token configurable --- config/config.yml_example_azure | 3 ++- pkg/cfg/oauth.go | 18 ++++++++++++++++++ pkg/providers/azure/azure.go | 21 ++++++++++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/config/config.yml_example_azure b/config/config.yml_example_azure index ebab962a..541ac4c6 100644 --- a/config/config.yml_example_azure +++ b/config/config.yml_example_azure @@ -22,4 +22,5 @@ oauth: - openid - email - profile - callback_url: https://vouch.yourdomain/auth \ No newline at end of file + callback_url: https://vouch.yourdomain/auth + azure_token: id_token # access_token and id_token supported \ No newline at end of file diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 8bfdd6df..4ef4626b 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -75,6 +75,7 @@ type oauthConfig struct { UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` PreferredDomain string `mapstructure:"preferredDomain"` + AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` } func configureOauth() error { @@ -137,6 +138,9 @@ func setProviderDefaults() { } else if GenOAuth.Provider == Providers.ADFS { setDefaultsADFS() configureOAuthClient() + } else if GenOAuth.Provider == Providers.Azure { + setDefaultsAzure() + configureOAuthClient() } else { // IndieAuth, OIDC, OpenStax, Nextcloud, Azure configureOAuthClient() @@ -169,6 +173,20 @@ func setDefaultsADFS() { OAuthopts = oauth2.SetAuthURLParam("resource", GenOAuth.RedirectURL) // Needed or all claims won't be included } +func setDefaultsAzure() { + log.Info("configuring Azure OAuth") + if len(GenOAuth.AzureToken) == 0 { + log.Info("Using Default Azure Token: access_token") + GenOAuth.AzureToken = "access_token" + } else if GenOAuth.AzureToken == "access_token" { + log.Info("Using Azure Token: access_token") + } else if GenOAuth.AzureToken == "id_token" { + log.Info("Using Azure Token: id_token") + } else { + log.Error("Azure Token must be either access_token or id_token") + } +} + func setDefaultsGitHub() { // log.Info("configuring GitHub OAuth") if GenOAuth.AuthURL == "" { diff --git a/pkg/providers/azure/azure.go b/pkg/providers/azure/azure.go index ef3c6c3a..793a8803 100644 --- a/pkg/providers/azure/azure.go +++ b/pkg/providers/azure/azure.go @@ -45,27 +45,38 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s // just going to extract user info and custom claims from there. azureUser := structs.AzureUser{} - tokenParts := strings.Split(ptokens.PAccessToken, ".") + var tokenParts []string + + if cfg.GenOAuth.AzureToken == "access_token" { + tokenParts = strings.Split(ptokens.PAccessToken, ".") + } else if cfg.GenOAuth.AzureToken == "id_token" { + tokenParts = strings.Split(ptokens.PIdToken, ".") + } else { + err = fmt.Errorf("Azure Token not access_token or id_token") + log.Error(err) + return err + } + if len(tokenParts) < 2 { err = fmt.Errorf("azure GetUserInfo: invalid token received; not enough parts") log.Error(err) return err } - accessTokenBytes, err := base64.RawURLEncoding.DecodeString(tokenParts[1]) + tokenBytes, err := base64.RawURLEncoding.DecodeString(tokenParts[1]) if err != nil { err = fmt.Errorf("azure GetUserInfo: decoding token failed: %+v", err) log.Error(err) return err } - if err = common.MapClaims(accessTokenBytes, customClaims); err != nil { + if err = common.MapClaims(tokenBytes, customClaims); err != nil { log.Error(err) return err } - log.Debugf("azure GetUserInfo: getting user info from accessToken: %+v", string(accessTokenBytes)) - if err = json.Unmarshal(accessTokenBytes, &azureUser); err != nil { + log.Debugf("azure GetUserInfo: getting user info from token: %+v", string(tokenBytes)) + if err = json.Unmarshal(tokenBytes, &azureUser); err != nil { err = fmt.Errorf("azure getUserInfoFromTokens: unpacking token into AzureUser failed: %+v", err) log.Error(err) return err From a049c8cbdc2ddb27b6677c3aa022fcc8c95fcc30 Mon Sep 17 00:00:00 2001 From: Simon Gottschlag Date: Mon, 5 Oct 2020 21:44:39 +0200 Subject: [PATCH 477/736] Use preferred username if UPN is unavailable --- pkg/structs/structs.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index e42c0d60..fe07b070 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -47,8 +47,9 @@ func (u *User) PrepareUserData() { // AzureUser is a retrieved and authenticated user from Azure AD type AzureUser struct { User - Sub string `json:"sub"` - UPN string `json:"upn"` + Sub string `json:"sub"` + UPN string `json:"upn"` + PreferredUsername string `json:"preferred_username"` } // PrepareUserData implement PersonalData interface @@ -60,6 +61,10 @@ func (u *AzureUser) PrepareUserData() { u.Username = u.UPN } + if u.Username == "" { + u.Username = u.PreferredUsername + } + if u.Email == "" { u.Email = u.UPN } From 7e45498ded84e3facea95bb2be0da8da05e23f0b Mon Sep 17 00:00:00 2001 From: Dag Wullt Date: Tue, 13 Oct 2020 16:05:43 +0200 Subject: [PATCH 478/736] Fix for example greedily matching paths The example nginx_with_vouch_single_server catches all paths that include /auth etc. this leads to unintended errors when the application has paths like https://application/system/authentication raising a 404 from vouch --- examples/nginx/single-file/nginx_with_vouch_single_server.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nginx/single-file/nginx_with_vouch_single_server.conf b/examples/nginx/single-file/nginx_with_vouch_single_server.conf index 2c1f8745..edee80a8 100644 --- a/examples/nginx/single-file/nginx_with_vouch_single_server.conf +++ b/examples/nginx/single-file/nginx_with_vouch_single_server.conf @@ -38,7 +38,7 @@ http { ssl_certificate_key /etc/letsencrypt/live/protectedapp.yourdomain.com/privkey.pem; # This location serves all of the paths vouch uses - location ~ /(auth|login|logout|static) { + location ~ ^/(auth|login|logout|static) { proxy_pass http://vouch; proxy_set_header Host $http_host; } From f17b2a9dcc8e08cd91b8e7f423b191d4f6185e49 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Thu, 12 Nov 2020 13:49:20 +0100 Subject: [PATCH 479/736] Add JWT algorithm support in config --- config/testing/test_config.yml | 2 +- config/testing/test_config_rsa.yml | 28 +++++++ pkg/cfg/cfg.go | 55 +++++++++++--- pkg/jwtmanager/jwtmanager.go | 114 +++++++++++++++++++++-------- pkg/jwtmanager/jwtmanager_test.go | 61 +++++++-------- 5 files changed, 188 insertions(+), 72 deletions(-) create mode 100644 config/testing/test_config_rsa.yml diff --git a/config/testing/test_config.yml b/config/testing/test_config.yml index 8143b4f6..3d72029b 100644 --- a/config/testing/test_config.yml +++ b/config/testing/test_config.yml @@ -17,7 +17,7 @@ vouch: name: VouchTestingSession jwt: - secret: testingsecret + secret: testingSecret oauth: provider: indieauth diff --git a/config/testing/test_config_rsa.yml b/config/testing/test_config_rsa.yml new file mode 100644 index 00000000..d865c8ed --- /dev/null +++ b/config/testing/test_config_rsa.yml @@ -0,0 +1,28 @@ +vouch: + logLevel: debug + listen: 0.0.0.0 + port: 9090 + domains: + - vouch.github.io + + whiteList: + - bob@yourdomain.com + - alice@yourdomain.com + - joe@yourdomain.com + + cookie: + name: vouchTestingCookie + + session: + name: VouchTestingSession + + jwt: + signing_method: RS512 + private_key_file: config/testing/rsa.key + public_key_file: config/testing/rsa.pub + +oauth: + provider: indieauth + client_id: http://vouch.github.io + auth_url: https://indielogin.com/auth + callback_url: http://vouch.github.io:9090/auth diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 3e8def28..7d9bed76 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -16,6 +16,7 @@ import ( "fmt" "net/http" "os" + "path" "path/filepath" "reflect" "strings" @@ -44,10 +45,13 @@ type Config struct { AllowAllUsers bool `mapstructure:"allowAllUsers"` PublicAccess bool `mapstructure:"publicAccess"` JWT struct { - MaxAge int `mapstructure:"maxAge"` // in minutes - Issuer string `mapstructure:"issuer"` - Secret string `mapstructure:"secret"` - Compress bool `mapstructure:"compress"` + SigningMethod string `mapstructure:"signing_method"` + MaxAge int `mapstructure:"maxAge"` // in minutes + Issuer string `mapstructure:"issuer"` + Secret string `mapstructure:"secret"` + PrivateKeyFile string `mapstructure:"private_key_file"` + PublicKeyFile string `mapstructure:"public_key_file"` + Compress bool `mapstructure:"compress"` } Cookie struct { Name string `mapstructure:"name"` @@ -293,7 +297,6 @@ func logConfigIfDebug() { } func fixConfigOptions() { - if Cfg.Cookie.MaxAge > Cfg.JWT.MaxAge { log.Warnf("setting `%s.cookie.maxage` to `%s.jwt.maxage` value of %d minutes (curently set to %d minutes)", Branding.LCName, Branding.LCName, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge) Cfg.Cookie.MaxAge = Cfg.JWT.MaxAge @@ -304,11 +307,25 @@ func fixConfigOptions() { Cfg.Headers.Redirect = "X-" + Branding.CcName + "-Requested-URI" } + if len(Cfg.JWT.SigningMethod) == 0 { + Cfg.JWT.SigningMethod = "HS256" + } else { + Cfg.JWT.SigningMethod = strings.ToUpper(Cfg.JWT.SigningMethod) + } + // jwt defaults - if len(Cfg.JWT.Secret) == 0 { + if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") && len(Cfg.JWT.Secret) == 0 { Cfg.JWT.Secret = getOrGenerateJWTSecret() } + if len(Cfg.JWT.PrivateKeyFile) > 0 && !path.IsAbs(Cfg.JWT.PrivateKeyFile) { + Cfg.JWT.PrivateKeyFile = path.Join(RootDir, Cfg.JWT.PrivateKeyFile) + } + + if len(Cfg.JWT.PublicKeyFile) > 0 && !path.IsAbs(Cfg.JWT.PublicKeyFile) { + Cfg.JWT.PublicKeyFile = path.Join(RootDir, Cfg.JWT.PublicKeyFile) + } + if len(Cfg.Session.Key) == 0 { log.Warn("generating random session.key") rstr, err := securerandom.Base64OfBytes(base64Bytes) @@ -353,7 +370,6 @@ func Get(key string) string { // basicTest just a quick sanity check to see if the config is sound func basicTest() error { - // check oauth config if err := oauthBasicTest(); err != nil { return err @@ -374,13 +390,33 @@ func basicTest() error { // issue a warning if the secret is too small log.Debugf("vouch.jwt.secret is %d characters long", len(Cfg.JWT.Secret)) - if len(Cfg.JWT.Secret) < minBase64Length { + + allowedSigningMethods := map[string]struct{}{ + "HS256": {}, "HS384": {}, "HS512": {}, // HMAC + "RS256": {}, "RS384": {}, "RS512": {}, // RSA + "ES256": {}, "ES384": {}, "ES512": {}, // ECDSA + } + if _, ok := allowedSigningMethods[Cfg.JWT.SigningMethod]; !ok { + return fmt.Errorf("configuration error: %s.jwt.signing_method value not allowed", Branding.LCName) + } + + if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") && len(Cfg.JWT.Secret) < minBase64Length { log.Errorf("Your secret is too short! (%d characters long). Please consider deleting %s to automatically generate a secret of %d characters", len(Cfg.JWT.Secret), Branding.LCName+".jwt.secret", minBase64Length) } + if strings.HasPrefix(Cfg.JWT.SigningMethod, "RS") || strings.HasPrefix(Cfg.JWT.SigningMethod, "ES") { + if len(Cfg.JWT.PublicKeyFile) == 0 { + log.Errorf("%s.jwt.public_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + } + + if len(Cfg.JWT.PrivateKeyFile) == 0 { + log.Errorf("%s.jwt.private_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + } + } + log.Debugf("vouch.session.key is %d characters long", len(Cfg.Session.Key)) if len(Cfg.Session.Key) < minBase64Length { log.Errorf("Your session key is too short! (%d characters long). Please consider deleting %s to automatically generate a secret of %d characters", @@ -481,7 +517,7 @@ func InitForTestPurposes() { // InitForTestPurposesWithProvider just for testing func InitForTestPurposesWithProvider(provider string) { Cfg = &Config{} // clear it out since we're called multiple times from subsequent tests - Logging.setLogLevel(zapcore.WarnLevel) + Logging.setLogLevel(zapcore.InfoLevel) setRootDir() // _, b, _, _ := runtime.Caller(0) // basepath := filepath.Dir(b) @@ -500,7 +536,6 @@ func InitForTestPurposesWithProvider(provider string) { setProviderDefaults() } fixConfigOptions() - // setDevelopmentLogger() // Needed to override the provider, which is otherwise set via yml diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index bd761eb8..fc0f0ad5 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -18,6 +18,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "strings" "time" @@ -73,6 +74,72 @@ func populateSites() { } } +func decryptionKey() (interface{}, error) { + if strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "HS") { + return []byte(cfg.Cfg.JWT.Secret), nil + } + + f, err := os.Open(cfg.Cfg.JWT.PublicKeyFile) + if err != nil { + return nil, fmt.Errorf("error opening Key %s: %s\n", cfg.Cfg.JWT.PrivateKeyFile, err) + } + + keyBytes, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("error reading Key: %s\n", err) + } + + var key interface{} + switch { + case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "RS"): + key, err = jwt.ParseRSAPublicKeyFromPEM(keyBytes) + case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "ES"): + key, err = jwt.ParseECPublicKeyFromPEM(keyBytes) + default: + // signingMethod should already have been validated, this should not happen + return nil, fmt.Errorf("unexpected signing method %s", cfg.Cfg.JWT.SigningMethod) + } + + if err != nil { + return nil, fmt.Errorf("error parsing Key: %s\n", err) + } + + return key, nil +} + +func signingKey() (interface{}, error) { + if strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "HS") { + return []byte(cfg.Cfg.JWT.Secret), nil + } + + f, err := os.Open(cfg.Cfg.JWT.PrivateKeyFile) + if err != nil { + return nil, fmt.Errorf("error opening RSA Key %s: %s\n", cfg.Cfg.JWT.PrivateKeyFile, err) + } + + keyBytes, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("error reading Key: %s\n", err) + } + + var key interface{} + switch { + case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "RS"): + key, err = jwt.ParseRSAPrivateKeyFromPEM(keyBytes) + case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "ES"): + key, err = jwt.ParseECPrivateKeyFromPEM(keyBytes) + default: + // We should have validated this before + return nil, fmt.Errorf("unexpected signing method %s", cfg.Cfg.JWT.SigningMethod) + } + + if err != nil { + return nil, fmt.Errorf("error parsing Key: %s\n", err) + } + + return key, nil +} + // CreateUserTokenString converts user to signed jwt func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, ptokens structs.PTokens) string { // User`token` @@ -89,7 +156,7 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt // https://github.com/vouch/vouch-proxy/issues/287 if cfg.Cfg.Headers.AccessToken == "" { claims.PAccessToken = "" - } + } if cfg.Cfg.Headers.IDToken == "" { claims.PIdToken = "" @@ -98,14 +165,16 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt claims.StandardClaims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix() // https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims - token := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), claims) - + token := jwt.NewWithClaims(jwt.GetSigningMethod(cfg.Cfg.JWT.SigningMethod), claims) // log.Debugf("token: %v", token) log.Debugf("token created, expires: %d diff from now: %d", claims.StandardClaims.ExpiresAt, claims.StandardClaims.ExpiresAt-time.Now().Unix()) - // token -> string. Only server knows this secret (foobar). - ss, err := token.SignedString([]byte(cfg.Cfg.JWT.Secret)) - // ss, err := token.SignedString([]byte("testing")) + key, err := signingKey() + if err != nil { + log.Errorf("%s", err) + } + + ss, err := token.SignedString(key) if ss == "" || err != nil { log.Errorf("signed token error: %s", err) } @@ -118,25 +187,6 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt return ss } -// TokenIsValid gett better error reporting -func TokenIsValid(token *jwt.Token, err error) bool { - if token.Valid { - return true - } else if ve, ok := err.(*jwt.ValidationError); ok { - if ve.Errors&jwt.ValidationErrorMalformed != 0 { - log.Errorf("token malformed") - } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { - // Token is either expired or not active yet - log.Errorf("token expired %s", err) - } else { - log.Errorf("token unknown error") - } - } else { - log.Errorf("token unknown error") - } - return false -} - // SiteInToken searches does the token contain the site? func SiteInToken(site string, token *jwt.Token) bool { if claims, ok := token.Claims.(*VouchClaims); ok { @@ -157,13 +207,18 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { log.Debugf("decompressed tokenString length %d", len(tokenString)) } + key, err := decryptionKey() + if err != nil { + log.Errorf("%s", err) + } + return jwt.ParseWithClaims(tokenString, &VouchClaims{}, func(token *jwt.Token) (interface{}, error) { // return jwt.ParseWithClaims(tokenString, &VouchClaims{}, func(token *jwt.Token) (interface{}, error) { - if token.Method != jwt.GetSigningMethod("HS256") { + if token.Method != jwt.GetSigningMethod(cfg.Cfg.JWT.SigningMethod) { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } - return []byte(cfg.Cfg.JWT.Secret), nil + return key, nil }) } @@ -181,10 +236,6 @@ func (claims *VouchClaims) SiteInClaims(site string) bool { // PTokenClaims get all the claims func PTokenClaims(ptoken *jwt.Token) (*VouchClaims, error) { - // func PTokenClaims(ptoken *jwt.Token) (VouchClaims, error) { - // return ptoken.Claims, nil - - // return ptoken.Claims.(*VouchClaims), nil ptokenClaims, ok := ptoken.Claims.(*VouchClaims) if !ok { log.Debugf("failed claims: %v %v", ptokenClaims, ptoken.Claims) @@ -195,7 +246,6 @@ func PTokenClaims(ptoken *jwt.Token) (*VouchClaims, error) { } func decodeAndDecompressTokenString(encgzipss string) string { - var gzipss []byte // gzipss, err := url.QueryUnescape(encgzipss) gzipss, err := base64.URLEncoding.DecodeString(encgzipss) diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index f696e0f2..62bebc3e 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -12,6 +12,8 @@ package jwtmanager import ( "encoding/json" + "os" + "path/filepath" "testing" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -42,37 +44,38 @@ var ( customClaims = structs.CustomClaims{} ) -func init() { - // log.SetLevel(log.DebugLevel) +func TestClaimsHMAC(t *testing.T) { + rootDir := os.Getenv(cfg.Branding.UCName + "_ROOT") + for _, cfgFile := range []string{"test_config.yml", "test_config_rsa.yml"} { + if err := os.Setenv(cfg.Branding.UCName+"_CONFIG", filepath.Join(rootDir, "config/testing", cfgFile)); err != nil { + t.Errorf("failed setting environment variable %s_CONFIG", cfg.Branding.UCName) + } - cfg.InitForTestPurposes() - Configure() + cfg.InitForTestPurposes() + Configure() - lc = VouchClaims{ - u1.Username, - Sites, - customClaims.Claims, - t1.PAccessToken, - t1.PIdToken, - StandardClaims, - } - json.Unmarshal([]byte(claimjson), &customClaims.Claims) -} + lc = VouchClaims{ + u1.Username, + Sites, + customClaims.Claims, + t1.PAccessToken, + t1.PIdToken, + StandardClaims, + } + json.Unmarshal([]byte(claimjson), &customClaims.Claims) -func TestClaims(t *testing.T) { - populateSites() - log.Debugf("jwt config %s %d", string(cfg.Cfg.JWT.Secret), cfg.Cfg.JWT.MaxAge) - assert.NotEmpty(t, cfg.Cfg.JWT.Secret) - assert.NotEmpty(t, cfg.Cfg.JWT.MaxAge) + populateSites() + log.Debugf("jwt config %s %d", string(cfg.Cfg.JWT.Secret), cfg.Cfg.JWT.MaxAge) + assert.NotEmpty(t, cfg.Cfg.JWT.SigningMethod) + assert.NotEmpty(t, cfg.Cfg.JWT.MaxAge) - // now := time.Now() - // d := time.Duration(ExpiresAtMinutes) * time.Minute - // log.Infof("lc d %s", d.String()) - // lc.StandardClaims.ExpiresAt = now.Add(time.Duration(ExpiresAtMinutes) * time.Minute).Unix() - // log.Infof("lc expiresAt %d", now.Unix()-lc.StandardClaims.ExpiresAt) - uts := CreateUserTokenString(u1, customClaims, t1) - utsParsed, _ := ParseTokenString(uts) - log.Infof("utsParsed: %+v", utsParsed) - log.Infof("Sites: %+v", Sites) - assert.True(t, SiteInToken(cfg.Cfg.Domains[0], utsParsed)) + uts := CreateUserTokenString(u1, customClaims, t1) + utsParsed, err := ParseTokenString(uts) + if err != nil { + t.Errorf("failed parsing token string: %s\n", err) + } + log.Infof("utsParsed: %+v", utsParsed) + log.Infof("Sites: %+v", Sites) + assert.True(t, SiteInToken(cfg.Cfg.Domains[0], utsParsed)) + } } From 8f67bb3b2748c2fe6c5fc4c6ee16512043efc84b Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Fri, 13 Nov 2020 01:50:05 +0100 Subject: [PATCH 480/736] update default config.yml example --- config/config.yml_example | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/config/config.yml_example b/config/config.yml_example index 95d7e5fb..5617d5fe 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -56,8 +56,15 @@ vouch: # - myOrg/myTeam jwt: + # signing_method: the algorithm used to sign the JWT. + # Can be one of HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512 + # Default is HS256 (HMAC) - and requires jwt.secret to be set + # Both RS* (RSA) and ES* (ECDSA) methods require jwt.private_key_file and + # jwt.public_key_file to be set. + # signing_method: HS256 + # secret - VOUCH_JWT_SECRET - # a random string used to cryptographically sign the jwt + # a random string used to cryptographically sign the jwt when signing_method is set to HS256, HS384 or HS512 # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes) # if the secret is not set here then Vouch Proxy will.. # - look for the secret in `./config/secret` @@ -66,6 +73,10 @@ vouch: # you'll want them all to have the same secret secret: your_random_string + # Path to the public/private key files when using an RSA or ECDSA signing method. + # public_key_file: + # private_key_file: + # issuer: Vouch # VOUCH_JWT_ISSUER # number of minutes until jwt expires - VOUCH_JWT_MAXAGE From 4f5605bb6f14a062808e146bd4ac4c9fd86ff1c7 Mon Sep 17 00:00:00 2001 From: Daniel Beneyto Date: Tue, 17 Nov 2020 09:07:14 +0100 Subject: [PATCH 481/736] Add TLS suport to http server --- .defaults.yml | 5 +++ config/config.yml_example | 5 +++ main.go | 5 +++ pkg/cfg/cfg.go | 8 ++++- pkg/cfg/tls.go | 69 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 pkg/cfg/tls.go diff --git a/.defaults.yml b/.defaults.yml index 5355712d..468c1c07 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -15,6 +15,11 @@ vouch: # whiteList: # teamWhitelist: + tls: + # cert: + # key: + profile: intermediate + jwt: # secret: issuer: Vouch diff --git a/config/config.yml_example b/config/config.yml_example index 95d7e5fb..71282569 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -55,6 +55,11 @@ vouch: # - myOrg # - myOrg/myTeam + tls: + # cert: /path/to/signed_cert_plus_intermediates # Path to certificate file + # key: /path/to/private_key # Path to key file + profile: intermediate # TLS configuration profile (modern, intermediate, old, default) + jwt: # secret - VOUCH_JWT_SECRET # a random string used to cryptographically sign the jwt diff --git a/main.go b/main.go index 043f3c0c..d6430062 100644 --- a/main.go +++ b/main.go @@ -166,6 +166,11 @@ func main() { ErrorLog: log.New(&fwdToZapWriter{fastlog}, "", 0), } + if cfg.Cfg.TLS.Cert != "" || cfg.Cfg.TLS.Key != "" { + srv.TLSConfig = cfg.TLSConfig(cfg.Cfg.TLS.Profile) + logger.Fatal(srv.ListenAndServeTLS(cfg.Cfg.TLS.Cert, cfg.Cfg.TLS.Key)) + } + logger.Fatal(srv.ListenAndServe()) } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 3e8def28..43cef43f 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -43,7 +43,13 @@ type Config struct { TeamWhiteList []string `mapstructure:"teamWhitelist"` AllowAllUsers bool `mapstructure:"allowAllUsers"` PublicAccess bool `mapstructure:"publicAccess"` - JWT struct { + + TLS struct { + Cert string `mapstructure:"cert"` + Key string `mapstructure:"key"` + Profile string `mapstructure:"profile"` + } + JWT struct { MaxAge int `mapstructure:"maxAge"` // in minutes Issuer string `mapstructure:"issuer"` Secret string `mapstructure:"secret"` diff --git a/pkg/cfg/tls.go b/pkg/cfg/tls.go new file mode 100644 index 00000000..020bcfca --- /dev/null +++ b/pkg/cfg/tls.go @@ -0,0 +1,69 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package cfg + +import ( + "crypto/tls" +) + +// TLSConfig config returns a *tls.Config with the specified profile (modern, intermediate, old, default) configuration. +func TLSConfig(profile string) *tls.Config { + c := &tls.Config{} + + // Source: https://ssl-config.mozilla.org/#server=go&version=1.14&config=modern&hsts=false&guideline=5.6 + switch profile { + case "modern": + c = &tls.Config{ + MinVersion: tls.VersionTLS13, + } + case "intermediate": + c = &tls.Config{ + MinVersion: tls.VersionTLS12, + CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, + PreferServerCipherSuites: true, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + } + case "old": + c = &tls.Config{ + MinVersion: tls.VersionTLS10, + PreferServerCipherSuites: true, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_128_CBC_SHA256, + tls.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + }, + } + } + + return c +} From fb89cfc6afc68b4ae5cc5b50b41d36bfe43da621 Mon Sep 17 00:00:00 2001 From: Daniel Beneyto Date: Wed, 18 Nov 2020 20:09:33 +0100 Subject: [PATCH 482/736] Implement suggestions --- README.md | 1 + config/config.yml_example | 7 ++++--- main.go | 14 ++++++++++---- pkg/cfg/cfg.go | 9 +++++++++ pkg/cfg/cfg_test.go | 25 +++++++++++++++++++++++++ pkg/cfg/tls_test.go | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 pkg/cfg/tls_test.go diff --git a/README.md b/README.md index 372291d1..244cd3f6 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) - [set `HTTP_PROXY` to relay Vouch Proxy IdP requests through an outbound proxy server](https://github.com/vouch/vouch-proxy/issues/291) - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) +- [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) Please do help us to expand this list. diff --git a/config/config.yml_example b/config/config.yml_example index 71282569..c714e674 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -56,9 +56,10 @@ vouch: # - myOrg/myTeam tls: - # cert: /path/to/signed_cert_plus_intermediates # Path to certificate file - # key: /path/to/private_key # Path to key file - profile: intermediate # TLS configuration profile (modern, intermediate, old, default) + # cert: /path/to/signed_cert_plus_intermediates # VOUCH_TLS_CERT + # key: /path/to/private_key # VOUCH_TLS_KEY + # profile - defines the TLS configuration profile (modern, intermediate, old, default) + profile: intermediate # VOUCH_TLS_PROFILE jwt: # secret - VOUCH_JWT_SECRET diff --git a/main.go b/main.go index d6430062..d6face4b 100644 --- a/main.go +++ b/main.go @@ -60,6 +60,10 @@ var ( logger *zap.SugaredLogger fastlog *zap.Logger help = flag.Bool("help", false, "show usage") + scheme = map[bool]string{ + false: "http", + true: "https", + } // doProfile = flag.Bool("profile", false, "run profiler at /debug/pprof") ) @@ -112,6 +116,7 @@ func main() { configure() var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) checkTCPPortAvailable(listen) + tls := (cfg.Cfg.TLS.Cert != "" && cfg.Cfg.TLS.Key != "") logger.Infow("starting "+cfg.Branding.FullName, // "semver": semver, @@ -120,7 +125,8 @@ func main() { "buildhost", host, "branch", branch, "semver", semver, - "listen", listen, + "listen", scheme[tls]+"://"+listen, + "tls", tls, "oauth.provider", cfg.GenOAuth.Provider) muxR := mux.NewRouter() @@ -166,13 +172,13 @@ func main() { ErrorLog: log.New(&fwdToZapWriter{fastlog}, "", 0), } - if cfg.Cfg.TLS.Cert != "" || cfg.Cfg.TLS.Key != "" { + if tls { srv.TLSConfig = cfg.TLSConfig(cfg.Cfg.TLS.Profile) logger.Fatal(srv.ListenAndServeTLS(cfg.Cfg.TLS.Cert, cfg.Cfg.TLS.Key)) + } else { + logger.Fatal(srv.ListenAndServe()) } - logger.Fatal(srv.ListenAndServe()) - } func checkTCPPortAvailable(listen string) { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 43cef43f..fae2bf90 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -403,6 +403,15 @@ func basicTest() error { if Cfg.Cookie.MaxAge > Cfg.JWT.MaxAge { return fmt.Errorf("configuration error: Cookie maxAge (%d) cannot be larger than the JWT maxAge (%d)", Cfg.Cookie.MaxAge, Cfg.JWT.MaxAge) } + + // check tls config + if Cfg.TLS.Key != "" && Cfg.TLS.Cert == "" { + return fmt.Errorf("configuration error: TLS certificate file not provided but TLS key is set (%s)", Cfg.TLS.Key) + } + if Cfg.TLS.Cert != "" && Cfg.TLS.Key == "" { + return fmt.Errorf("configuration error: TLS key file not provided but TLS certificate is set (%s)", Cfg.TLS.Cert) + } + return nil } diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index d6dfb660..7cfe6cf0 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -54,6 +54,31 @@ func TestConfigEnvPrecedence(t *testing.T) { } +func TestConfigWithTLS(t *testing.T) { + tests := []struct { + name string + tlsKeyFile string + tlsCertFile string + wantErr bool + }{ + {"TLSConfigOK", "/path/to/key", "/path/to/cert", false}, + {"TLSConfigKONoCert", "/path/to/key", "", true}, + {"TLSConfigKONoKey", "", "/path/to/cert", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Cleanup(cleanupEnv) + InitForTestPurposes() + Cfg.TLS.Cert = tt.tlsCertFile + Cfg.TLS.Key = tt.tlsKeyFile + err := ValidateConfiguration() + + if (err != nil) != tt.wantErr { + t.Errorf("error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} func TestSetGitHubDefaults(t *testing.T) { InitForTestPurposesWithProvider("github") assert.Equal(t, []string{"read:user"}, GenOAuth.Scopes) diff --git a/pkg/cfg/tls_test.go b/pkg/cfg/tls_test.go new file mode 100644 index 00000000..f2bf2ca7 --- /dev/null +++ b/pkg/cfg/tls_test.go @@ -0,0 +1,37 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package cfg + +import ( + "crypto/tls" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTLSConfig(t *testing.T) { + tests := []struct { + name string + profile string + wantTLSMinVersion uint16 + }{ + {"TLSDefaultProfile", "", 0}, + {"TLSModernProfile", "modern", tls.VersionTLS13}, + {"TLSIntermediateProfile", "intermediate", tls.VersionTLS12}, + {"TLSOldProfile", "old", tls.VersionTLS10}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tlsConfig := TLSConfig(tt.profile) + assert.Equal(t, tt.wantTLSMinVersion, tlsConfig.MinVersion) + }) + } +} From 910943a92d972f3a98f103fead4b49a01435bd75 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Thu, 19 Nov 2020 13:58:08 +0000 Subject: [PATCH 483/736] prevent redirect to other domains. If cookie.domain is set to blah.com, and a redirect url is provided as blah.com.my.custom.domain then vouch will reject it and not send the user back to the incorrect domain. --- config/testing/handler_login_url.yml | 1 + handlers/login.go | 3 ++- handlers/login_test.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/testing/handler_login_url.yml b/config/testing/handler_login_url.yml index ff7fdb9a..a69a405f 100644 --- a/config/testing/handler_login_url.yml +++ b/config/testing/handler_login_url.yml @@ -4,6 +4,7 @@ vouch: cookie: secure: false + domain: example.com jwt: secret: testingsecret diff --git a/handlers/login.go b/handlers/login.go index 038f4ebc..0c932feb 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -212,7 +212,8 @@ func getValidRequestedURL(r *http.Request) (string, error) { if cfg.GenOAuth.Provider != cfg.Providers.IndieAuth { d := domains.Matches(hostname) if d == "" { - if cfg.Cfg.Cookie.Domain == "" || !strings.Contains(hostname, cfg.Cfg.Cookie.Domain) { + inCookieDomain := (hostname == cfg.Cfg.Cookie.Domain || strings.HasSuffix(hostname, "." + cfg.Cfg.Cookie.Domain)) + if cfg.Cfg.Cookie.Domain == "" || !inCookieDomain { return "", fmt.Errorf("%w: not within a %s managed domain", errInvalidURL, cfg.Branding.FullName) } } diff --git a/handlers/login_test.go b/handlers/login_test.go index 14f5270a..240e1a4a 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -105,6 +105,7 @@ func Test_getValidRequestedURL(t *testing.T) { {"redirection chaining escaped https://", "http://example.com/dest?url=https%3a%2f%2fsomeplaceelse.com", "", true}, {"data uri", "http://example.com/dest?url=data:text/plain,Example+Text", "", true}, {"javascript uri", "http://example.com/dest?url=javascript:alert(1)", "", true}, + {"not in domain but contains domain", "http://example.com.somewherelse.com/", "", true}, {"not in domain", "http://somewherelse.com/", "", true}, {"should warn", "https://example.com/", "https://example.com/", false}, {"should be fine", "http://example.com/", "http://example.com/", false}, From 714561eb6347c448c1349ca2d0c0a8b77b9247fd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 19 Nov 2020 16:31:37 -0800 Subject: [PATCH 484/736] explain what Vouch Proxy does and include diagrams --- README.md | 18 +++++++++++++++++- .../nginx-vouch-private_appA_appB_appC.png | Bin 0 -> 21708 bytes examples/nginx-vouch-private_simple.png | Bin 0 -> 14615 bytes 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 examples/nginx-vouch-private_appA_appB_appC.png create mode 100644 examples/nginx-vouch-private_simple.png diff --git a/README.md b/README.md index bf54abdc..a5c71c53 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Docker pulls](https://img.shields.io/docker/pulls/voucher/vouch-proxy.svg)](https://hub.docker.com/r/voucher/vouch-proxy/) [![GitHub version](https://badge.fury.io/gh/vouch%2Fvouch-proxy.svg)](https://badge.fury.io/gh/vouch%2Fvouch-proxy) -an SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. +An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. Vouch Proxy supports many OAuth login providers and can enforce authentication to... @@ -30,6 +30,20 @@ Please do let us know when you have deployed Vouch Proxy with your preffered IdP If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be less than 1ms +## What Vouch Proxy Does... + +Vouch Proxy (VP) forces visitors to login and authenticate with an [IdP](https://en.wikipedia.org/wiki/Identity_provider) (such as one of the services listed above) before allowing them access to a website. + +![Vouch Proxy protects websites](https://github.com/vouch/vouch-proxy/blob/master/examples/nginx-vouch-private_simple.png?raw=true) + +VP can also be used as a Single Sign On (SSO) solution to protect all web applications in the same domain. + +![Vouch Proxy is a Single Sign On solution](https://github.com/vouch/vouch-proxy/blob/master/examples/nginx-vouch-private_appA_appB_appC.png?raw=true) + +After a visitor logs in Vouch Proxy allows access to the protected websites for several hours. Every request is checked by VP to ensure that it is valid. + +VP can send the visitor's email, name and other information which the IdP provides (including access tokens) to the web application as HTTP headers. VP can be used to replace application user management entirely. + ## Installation and Configuration Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L23-L33) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L81-L82) to `yourdomain.com`. @@ -169,6 +183,8 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con Please do help us to expand this list. +All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) + ## Running from Docker ```bash diff --git a/examples/nginx-vouch-private_appA_appB_appC.png b/examples/nginx-vouch-private_appA_appB_appC.png new file mode 100644 index 0000000000000000000000000000000000000000..4bb54ccef2ab84f47c0929f7d03307674fe47ca1 GIT binary patch literal 21708 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 G7ycK~85>vt literal 0 HcmV?d00001 From 3b151a3f3f55cd9f98e4a5f0820106d7ed9ffbe0 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sun, 29 Nov 2020 11:38:16 +0100 Subject: [PATCH 485/736] add keys for tests --- config/testing/rsa.key | 51 ++++++++++++++++++++++++++++++++++++ config/testing/rsa.pub | 14 ++++++++++ handlers/login.go | 2 +- pkg/jwtmanager/jwtmanager.go | 2 +- 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 config/testing/rsa.key create mode 100644 config/testing/rsa.pub diff --git a/config/testing/rsa.key b/config/testing/rsa.key new file mode 100644 index 00000000..9a3507ef --- /dev/null +++ b/config/testing/rsa.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/config/testing/rsa.pub b/config/testing/rsa.pub new file mode 100644 index 00000000..904fa13a --- /dev/null +++ b/config/testing/rsa.pub @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtLXbZPJCybcLwegsi66v +NjmXZIm42kAbp/tBoH7UwJIGjv4b0Yn8jvkQKEdONNKvDQjcjrlfMCgeeV5rXLvK +iUhCMf3KbRKcGdxWESYtUF1hd3qwubQCed0Z4xJgKegDFgUCasZMQUekwktgwMqX +bGy19i2N9AHNCjXyLLQXV4ja3tVgXev8AJF0FAaYPLB2T7PFZ3xqH6kLFEWqSN6g +oF+cHIj0sCw6yRDBJmqU4oSwxCqEH3mQNYw3UK2fV/VGrNf586OHqitdfATWdQmc +5cXYeSGCqsM4OygM8VIs27SACoR0rCQT8daK2cBHPvG4YoHkUWx4STXscIMxdp5p +nLjZZxBg9KOFPapZrMAu+v8d2wgs30W8YgODxlcKK4ZVOG1B1naFT93kStvWeeNf +rswlSIo1MqyMxJ4MP5mRzvcA5xEFBuehv1XsdhxOkwXw7vMBv2DfavHxANiOP/yj +5nr3P8pakPw8LGSJFknmJ5CodXUCp4QjeCYoPB1aOKRLj1s2m/6opiIEy4he77Ev ++CYwLX7L3vljPwHwlpgSN5IT/XxkvAH/7MZB3gVfNY72lkjat5SSlVjycaHf/a96 +EPOKhEe+0LtAZEEbOtzlmM+7PLijJt/piX8/QZlSIh0hhhYCzKvOFfCNmpeDNwbI +aDFz3A4JrGgKmawgtzRdT3sCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/handlers/login.go b/handlers/login.go index 0c932feb..387c0145 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -212,7 +212,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { if cfg.GenOAuth.Provider != cfg.Providers.IndieAuth { d := domains.Matches(hostname) if d == "" { - inCookieDomain := (hostname == cfg.Cfg.Cookie.Domain || strings.HasSuffix(hostname, "." + cfg.Cfg.Cookie.Domain)) + inCookieDomain := (hostname == cfg.Cfg.Cookie.Domain || strings.HasSuffix(hostname, "."+cfg.Cfg.Cookie.Domain)) if cfg.Cfg.Cookie.Domain == "" || !inCookieDomain { return "", fmt.Errorf("%w: not within a %s managed domain", errInvalidURL, cfg.Branding.FullName) } diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index fc0f0ad5..25ad7cf1 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -81,7 +81,7 @@ func decryptionKey() (interface{}, error) { f, err := os.Open(cfg.Cfg.JWT.PublicKeyFile) if err != nil { - return nil, fmt.Errorf("error opening Key %s: %s\n", cfg.Cfg.JWT.PrivateKeyFile, err) + return nil, fmt.Errorf("error opening Key %s: %s\n", cfg.Cfg.JWT.PublicKeyFile, err) } keyBytes, err := ioutil.ReadAll(f) From 2eccc636a5fc9990fadd9ca23ea14d8dd7a78adc Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sun, 29 Nov 2020 12:06:22 +0100 Subject: [PATCH 486/736] better cfg error handling, add gitguardian config --- .gitguardian.yml | 2 ++ pkg/cfg/cfg.go | 28 +++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .gitguardian.yml diff --git a/.gitguardian.yml b/.gitguardian.yml new file mode 100644 index 00000000..c25f47f4 --- /dev/null +++ b/.gitguardian.yml @@ -0,0 +1,2 @@ +paths-ignore: + - 'config/testing/rsa*' \ No newline at end of file diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 7d9bed76..d75e7202 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -400,20 +400,34 @@ func basicTest() error { return fmt.Errorf("configuration error: %s.jwt.signing_method value not allowed", Branding.LCName) } - if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") && len(Cfg.JWT.Secret) < minBase64Length { - log.Errorf("Your secret is too short! (%d characters long). Please consider deleting %s to automatically generate a secret of %d characters", - len(Cfg.JWT.Secret), - Branding.LCName+".jwt.secret", - minBase64Length) + if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") { + if len(Cfg.JWT.PublicKeyFile) > 0 { + return fmt.Errorf("%s.jwt.public_key_file should not be set when using signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + } + + if len(Cfg.JWT.PrivateKeyFile) > 9 { + return fmt.Errorf("%s.jwt.private_key_file should not be set when using signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + } + + if len(Cfg.JWT.Secret) < minBase64Length { + log.Errorf("Your secret is too short! (%d characters long). Please consider deleting %s to automatically generate a secret of %d characters", + len(Cfg.JWT.Secret), + Branding.LCName+".jwt.secret", + minBase64Length) + } } if strings.HasPrefix(Cfg.JWT.SigningMethod, "RS") || strings.HasPrefix(Cfg.JWT.SigningMethod, "ES") { + if len(Cfg.JWT.Secret) > 0 { + return fmt.Errorf("%s.jwt.secret should not be set when using signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + } + if len(Cfg.JWT.PublicKeyFile) == 0 { - log.Errorf("%s.jwt.public_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + return fmt.Errorf("%s.jwt.public_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) } if len(Cfg.JWT.PrivateKeyFile) == 0 { - log.Errorf("%s.jwt.private_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) + return fmt.Errorf("%s.jwt.private_key_file needs to be set for signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) } } From da61f2401f257dc64e46c6af01cfbbc5eb386a3a Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sun, 29 Nov 2020 12:51:37 +0100 Subject: [PATCH 487/736] Add parsing test --- pkg/cfg/cfg_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index d6dfb660..e776ebb0 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -69,6 +69,12 @@ func TestSetGitHubDefaultsWithTeamWhitelist(t *testing.T) { assert.Contains(t, GenOAuth.Scopes, "read:org") } +func TestCheckConfigWithRSA(t *testing.T) { + setUp("config/testing/test_config_rsa.yml") + assert.Contains(t, Cfg.JWT.PrivateKeyFile, "config/testing/rsa.key") + assert.Contains(t, Cfg.JWT.PublicKeyFile, "config/testing/rsa.pub") +} + func Test_claimToHeader(t *testing.T) { tests := []struct { name string From d505c38e16eadd9f7bfbe4fdeab13afaa50fad4a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 4 Dec 2020 15:00:49 -0800 Subject: [PATCH 488/736] #303 env var, check cfg, refactor oauthLoginURL --- config/config.yml_example | 27 ++++++++--------- handlers/login.go | 61 ++++++++++++++++++--------------------- pkg/cfg/oauth.go | 3 ++ 3 files changed, 45 insertions(+), 46 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index ca91279c..805ce0e2 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -165,19 +165,20 @@ vouch: # # environmental variables for OAuth config: -# provider: OAUTH_PROVIDER -# client_id: OAUTH_CLIENT_ID -# client_secret: OAUTH_CLIENT_SECRET -# auth_url: OAUTH_AUTH_URL -# token_url: OAUTH_TOKEN_URL -# end_session_endpoint: OAUTH_END_SESSION_ENDPOINT -# callback_url: OAUTH_CALLBACK_URL -# user_info_url: OAUTH_USER_INFO_URL -# user_team_url: OAUTH_USER_TEAM_URL -# user_org_url: OAUTH_USER_ORG_URL -# preferreddomain: OAUTH_PREFERREDDOMAIN -# callback_urls: OAUTH_CALLBACK_URLS -# scopes: OAUTH_SCOPES +# provider: OAUTH_PROVIDER +# client_id: OAUTH_CLIENT_ID +# client_secret: OAUTH_CLIENT_SECRET +# auth_url: OAUTH_AUTH_URL +# token_url: OAUTH_TOKEN_URL +# end_session_endpoint: OAUTH_END_SESSION_ENDPOINT +# callback_url: OAUTH_CALLBACK_URL +# user_info_url: OAUTH_USER_INFO_URL +# user_team_url: OAUTH_USER_TEAM_URL +# user_org_url: OAUTH_USER_ORG_URL +# preferreddomain: OAUTH_PREFERREDDOMAIN +# callback_urls: OAUTH_CALLBACK_URLS +# scopes: OAUTH_SCOPES +# code_challenge_method: OAUTH_CODE_CHALLENGE_METHOD # # configure ONLY ONE of the following oauth providers diff --git a/handlers/login.go b/handlers/login.go index 13026b1b..a762cc5b 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -13,12 +13,12 @@ package handlers import ( "errors" "fmt" - "github.com/gorilla/sessions" "net/http" "net/url" "regexp" "strings" + "github.com/gorilla/sessions" cv "github.com/nirasan/go-oauth-pkce-code-verifier" "github.com/theckman/go-securerandom" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -237,45 +237,40 @@ func getValidRequestedURL(r *http.Request) (string, error) { func oauthLoginURL(r *http.Request, session sessions.Session) string { // State can be some kind of random generated hash string. // See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12 - var lurl string var state string = session.Values["state"].(string) + opts := []oauth2.AuthCodeOption{} if cfg.GenOAuth.Provider == cfg.Providers.IndieAuth { - lurl = cfg.OAuthClient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) - } else if cfg.GenOAuth.Provider == cfg.Providers.ADFS { - lurl = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) - } else { - // cfg.OAuthClient.RedirectURL is set in cfg - // this checks the multiple redirect case for multiple matching domains - if len(cfg.GenOAuth.RedirectURLs) > 0 { - found := false - domain := domains.Matches(r.Host) - log.Debugf("/login looking for callback_url matching %s", domain) - for _, v := range cfg.GenOAuth.RedirectURLs { - if strings.Contains(v, domain) { - found = true - log.Debugf("/login callback_url set to %s", v) - cfg.OAuthClient.RedirectURL = v - break - } - } - if !found { - log.Infof("/login no callback_url matched %s (is the `Host` header being passed to Vouch Proxy?)", domain) + return cfg.OAuthClient.AuthCodeURL(state, oauth2.SetAuthURLParam("response_type", "id")) + } + + // cfg.OAuthClient.RedirectURL is set in cfg + // this checks the multiple redirect case for multiple matching domains + if len(cfg.GenOAuth.RedirectURLs) > 0 { + found := false + domain := domains.Matches(r.Host) + log.Debugf("/login looking for callback_url matching %s", domain) + for _, v := range cfg.GenOAuth.RedirectURLs { + if strings.Contains(v, domain) { + found = true + log.Debugf("/login callback_url set to %s", v) + cfg.OAuthClient.RedirectURL = v + break } } - // Google and a few other IdPs allow other options to be set - if cfg.OAuthopts != nil { - lurl = cfg.OAuthClient.AuthCodeURL(state, cfg.OAuthopts) - } else { - lurl = cfg.OAuthClient.AuthCodeURL(state) + if !found { + log.Infof("/login no callback_url matched %s (is the `Host` header being passed to Vouch Proxy?)", domain) } + } + // append code challenge and code challenge method query parameters if enabled - // append code challenge and code challenge method query parameters if enabled - if cfg.GenOAuth.CodeChallengeMethod != "" { - lurl = fmt.Sprintf("%s&code_challenge_method=%s&code_challenge=%s", lurl, cfg.GenOAuth.CodeChallengeMethod, session.Values["codeChallenge"].(string)) - } + if cfg.GenOAuth.CodeChallengeMethod != "" { + opts = append(opts, oauth2.SetAuthURLParam("code_challenge_method", cfg.GenOAuth.CodeChallengeMethod)) + opts = append(opts, oauth2.SetAuthURLParam("code_challenge", session.Values["codeChallenge"].(string))) + } + if cfg.OAuthopts != nil { + opts = append(opts, cfg.OAuthopts) } - // log.Debugf("loginURL %s", url) - return lurl + return cfg.OAuthClient.AuthCodeURL(state, opts...) } var regExJustAlphaNum, _ = regexp.Compile("[^a-zA-Z0-9]+") diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 7037354b..027d4d6d 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -111,6 +111,8 @@ func oauthBasicTest() error { case GenOAuth.Provider != Providers.Google && GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.HomeAssistant && GenOAuth.Provider != Providers.ADFS && GenOAuth.UserInfoURL == "": // everyone except IndieAuth, Google and ADFS has an userInfoURL return errors.New("configuration error: oauth.user_info_url not found") + case GenOAuth.CodeChallengeMethod != "" && (GenOAuth.CodeChallengeMethod != "plain" && GenOAuth.CodeChallengeMethod != "S256"): + return errors.New("configuration error: oauth.code_challenge_method must be either 'S256' or 'plain'") } if GenOAuth.RedirectURL != "" { @@ -163,6 +165,7 @@ func setDefaultsGoogle() { log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) OAuthopts = oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain) } + GenOAuth.CodeChallengeMethod = "S256" } func setDefaultsADFS() { From dcb40c0aa446345f7d2261e6fdaecb8e0cbc9fd6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sun, 6 Dec 2020 15:19:07 -0800 Subject: [PATCH 489/736] #303 PKCE is default for IndieAuth, Github, Azure --- pkg/cfg/oauth.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 027d4d6d..e5d7b41d 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -140,8 +140,11 @@ func setProviderDefaults() { } else if GenOAuth.Provider == Providers.ADFS { setDefaultsADFS() configureOAuthClient() + } else if GenOAuth.Provider == Providers.IndieAuth || GenOAuth.Provider == Providers.Azure { + GenOAuth.CodeChallengeMethod = "S256" + configureOAuthClient() } else { - // IndieAuth, OIDC, OpenStax, Nextcloud, Azure + // OIDC, OpenStax, Nextcloud configureOAuthClient() } } @@ -199,6 +202,7 @@ func setDefaultsGitHub() { GenOAuth.Scopes = append(GenOAuth.Scopes, "read:org") } } + GenOAuth.CodeChallengeMethod = "S256" } func configureOAuthClient() { From d08a4f79441870dc560c3a0ebcab84de7e513ee5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sun, 6 Dec 2020 19:02:32 -0800 Subject: [PATCH 490/736] #314 exit on bad config --- pkg/cfg/oauth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 3d75a9db..cbf7c5de 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -205,7 +205,7 @@ func setDefaultsAzure() { } else if GenOAuth.AzureToken == "id_token" { log.Info("Using Azure Token: id_token") } else { - log.Fatal("Azure Token must be either access_token or id_token") + log.Fatal("'oauth.azure_token' must be either 'access_token' or 'id_token'") } GenOAuth.CodeChallengeMethod = "S256" } From b205a1b9f7301149d212d67c9d6773deb05d53db Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 7 Dec 2020 04:03:57 -0800 Subject: [PATCH 491/736] #314 exit on bad config --- pkg/cfg/oauth.go | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 3d75a9db..40dc4306 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -62,22 +62,6 @@ type OAuthProviders struct { // `envconfig` tag is for env var support // https://github.com/kelseyhightower/envconfig type oauthConfig struct { -<<<<<<< HEAD - Provider string `mapstructure:"provider"` - ClientID string `mapstructure:"client_id" envconfig:"client_id"` - ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` - AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` - TokenURL string `mapstructure:"token_url" envconfig:"token_url"` - LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` - RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` - RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` - Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` - UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` - UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` - PreferredDomain string `mapstructure:"preferredDomain"` - AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` -======= Provider string `mapstructure:"provider"` ClientID string `mapstructure:"client_id" envconfig:"client_id"` ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` @@ -91,8 +75,8 @@ type oauthConfig struct { UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` PreferredDomain string `mapstructure:"preferredDomain"` + AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` ->>>>>>> master } func configureOauth() error { @@ -157,7 +141,7 @@ func setProviderDefaults() { } else if GenOAuth.Provider == Providers.ADFS { setDefaultsADFS() configureOAuthClient() - } else if GenOAuth.Provider == Providers.Azure { + } else if GenOAuth.Provider == Providers.Azure { setDefaultsAzure() } else if GenOAuth.Provider == Providers.IndieAuth { GenOAuth.CodeChallengeMethod = "S256" @@ -205,7 +189,7 @@ func setDefaultsAzure() { } else if GenOAuth.AzureToken == "id_token" { log.Info("Using Azure Token: id_token") } else { - log.Fatal("Azure Token must be either access_token or id_token") + log.Fatal("'oauth.azure_token' must be either 'access_token' or 'id_token'") } GenOAuth.CodeChallengeMethod = "S256" } From 0746ee9c177c9b82f10ee8b6e484043d5a341745 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 7 Dec 2020 18:13:17 -0800 Subject: [PATCH 492/736] improve do.sh docu-messaging --- do.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/do.sh b/do.sh index 2137db2c..3401ede8 100755 --- a/do.sh +++ b/do.sh @@ -105,11 +105,14 @@ bug_report() { usage: - $0 bug_report redacted_string redacted_string + $0 bug_report redacted_string redacted_string EOF exit 1; fi + echo -e "#\n# If sensitive information is still visible in the output, first try appending the string.." + echo -e "#\n# '$0 bug_report badstring1 badstring2'\n#\n" + echo -e "#\n# Please consider submitting a PR for the './do.sh _redact' routine if you feel that it should be improved.\n#" echo -e "\n-------------------------\n\n#\n# redacted Vouch Proxy ${CONFIG}\n# $(date -I)\n#\n" cat $CONFIG | _redact @@ -321,25 +324,25 @@ gosec() { usage() { cat < Date: Mon, 7 Dec 2020 18:13:47 -0800 Subject: [PATCH 493/736] minor changes flagged by gosec --- pkg/cfg/cfg.go | 10 +++++++--- pkg/healthcheck/healthcheck.go | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 3e8def28..7ec23fcd 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -178,7 +178,9 @@ func Configure() { if err := configureOauth(); err == nil { setProviderDefaults() } - cleanClaimsHeaders() + if err := cleanClaimsHeaders(); err != nil { + log.Fatalf("%w: %w", configFileErr, err) + } if *CmdLine.port != -1 { Cfg.Port = *CmdLine.port } @@ -494,7 +496,9 @@ func InitForTestPurposesWithProvider(provider string) { // Configure() // setRootDir() setDefaults() - parseConfigFile() + if err := parseConfigFile(); err != nil { + log.Error(err) + } configureFromEnv() if err := configureOauth(); err == nil { setProviderDefaults() @@ -508,6 +512,6 @@ func InitForTestPurposesWithProvider(provider string) { GenOAuth.Provider = provider setProviderDefaults() } - cleanClaimsHeaders() + _ = cleanClaimsHeaders() } diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go index 9917eef1..be974171 100644 --- a/pkg/healthcheck/healthcheck.go +++ b/pkg/healthcheck/healthcheck.go @@ -42,7 +42,8 @@ func CheckAndExitIfIsHealthCheck() { func healthcheck() { url := fmt.Sprintf("http://%s:%d/healthcheck", cfg.Cfg.Listen, cfg.Cfg.Port) - log.Debug("Invoking healthcheck on URL ", url) + log.Debugf("Invoking healthcheck on %s", url) + // #nosec - turn off gosec checking which flags `http.Get(url)` resp, err := http.Get(url) if err == nil { body, err := ioutil.ReadAll(resp.Body) From b314dd53c3ccc8782f304c1b5652f6a160f375eb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 7 Dec 2020 18:26:51 -0800 Subject: [PATCH 494/736] explicitly name fields in 'lc' struct init --- handlers/handlers_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 6a968940..d1ff237f 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -141,12 +141,12 @@ func init() { // log.SetLevel(log.DebugLevel) lc = jwtmanager.VouchClaims{ - u1.Username, - jwtmanager.Sites, - customClaims.Claims, - t1.PAccessToken, - t1.PIdToken, - jwtmanager.StandardClaims, + Username: u1.Username, + Sites: jwtmanager.Sites, + CustomClaims: customClaims.Claims, + PAccessToken: t1.PAccessToken, + PIdToken: t1.PIdToken, + StandardClaims: jwtmanager.StandardClaims, } json.Unmarshal([]byte(claimjson), &customClaims.Claims) } From 81f50c0f29a99ecba42ec3ca5abaf3c7c404f7fa Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 7 Dec 2020 19:31:52 -0800 Subject: [PATCH 495/736] #297 create self signed certs --- .gitignore | 1 + do.sh | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index 5ba43587..69943ee8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ config/secret !config/testing/* pkg/model/storage-test.db .vscode/* +certs/* coverage.out coverage.html.env_google .env* diff --git a/do.sh b/do.sh index 2137db2c..3159000d 100755 --- a/do.sh +++ b/do.sh @@ -318,6 +318,17 @@ gosec() { # segfault's without exec since it would just call this function infinitely :) exec gosec ./... } + +selfcert() { + # https://stackoverflow.com/questions/63588254/how-to-set-up-an-https-server-with-a-self-signed-certificate-in-golang + set -e + mkdir -p $SDIR/certs + # openssl genrsa -out $SDIR/certs/server.key 2048 + openssl ecparam -genkey -name secp384r1 -out $SDIR/certs/server.key + openssl req -new -x509 -sha256 -key $SDIR/certs/server.key -out $SDIR/certs/server.crt -days 3650 + echo -e "created self signed certs in '$SDIR/certs'\n" +} + usage() { cat < Date: Fri, 11 Dec 2020 15:58:47 +0100 Subject: [PATCH 496/736] add toc to readme to get an overview --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index c817eee3..907fcc93 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,29 @@ Please do let us know when you have deployed Vouch Proxy with your preffered IdP If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be less than 1ms +--- +## Table of Contents + +* [What Vouch Proxy Does...](#what-vouch-proxy-does) +* [Installation and Configuration](#installation-and-configuration) +* [Configuring Vouch Proxy using Environmental Variables](#configuring-vouch-proxy-using-environmental-variables) +* [More advanced configurations](#more-advanced-configurations) +* [Running from Docker](#running-from-docker) +* [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) +* [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) +* [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) +* [Troubleshooting, Support and Feature Requests] + (#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) + (Read this before submitting an issue at GitHub) + + [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) + + [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) + + [submitting a Pull Request for a new feature](#submitting-a-pull-request-for-a-new-feature) +* [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) +* [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) + +--- + + ## What Vouch Proxy Does... Vouch Proxy (VP) forces visitors to login and authenticate with an [IdP](https://en.wikipedia.org/wiki/Identity_provider) (such as one of the services listed above) before allowing them access to a website. From 4b1942823b04edba815390da69e4936ae8624a05 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:03:10 +0100 Subject: [PATCH 497/736] bugfix + header test --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 907fcc93..69242f0d 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim * [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) * [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) * [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) -* [Troubleshooting, Support and Feature Requests] - (#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) +* [Troubleshooting, Support and Feature Requests](#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) (Read this before submitting an issue at GitHub) + [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) + [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) @@ -205,6 +204,8 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) +##### Scopes and Claims + Please do help us to expand this list. All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) From 59e8436d04f11ffba140aef04866de27ea50458b Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:03:51 +0100 Subject: [PATCH 498/736] header test v2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69242f0d..412271c5 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) -##### Scopes and Claims +#### Scopes and Claims Please do help us to expand this list. From 50f6f46c94e5c9540b9c39f4800b5bdb3667dac1 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:05:18 +0100 Subject: [PATCH 499/736] add link to toc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 412271c5..6c5c88f5 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim * [Installation and Configuration](#installation-and-configuration) * [Configuring Vouch Proxy using Environmental Variables](#configuring-vouch-proxy-using-environmental-variables) * [More advanced configurations](#more-advanced-configurations) + + [Scopes and Claims](#scopes-and-claims) * [Running from Docker](#running-from-docker) * [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) * [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) From c3d00831b01945c1aa3a33754a5d0d476ac5b890 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:28:23 +0100 Subject: [PATCH 500/736] add scopes example config --- config/scopes_and_claims_config.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 config/scopes_and_claims_config.yml diff --git a/config/scopes_and_claims_config.yml b/config/scopes_and_claims_config.yml new file mode 100644 index 00000000..757b5eb8 --- /dev/null +++ b/config/scopes_and_claims_config.yml @@ -0,0 +1,23 @@ +vouch: + # .... domain configuration goes here + + headers: + # The idtoken is used for debugging during configuration + # use the idtoken to make sure the oauth provider returns the necessary claims + idtoken: X-Vouch-IdP-IdToken + + # make sure to list all the claims you need + # Note: they will be stored in the cookie AND header and get sent with each request + claims: + - sub + - name + - email + - email_verified + +oauth: + # .... your provider config goes here + scopes: + # make sure to set the required scopes + - openid + - email + - profile From 17c437e8b8de892a9f0b6a96d38dafc9c3f86c17 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:30:37 +0100 Subject: [PATCH 501/736] added steps --- README.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/README.md b/README.md index 6c5c88f5..90084015 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,103 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con #### Scopes and Claims +With vouch-proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. +Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are +extracted and stored in the vouch cookie. + +Warning: Userinfo will get added to the Vouch cookie and (possibly) make it large. The Vouch cookie may get split up into several cookies, but if you need it, you need it. +With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. + +Here is a protocol to set up `scopes` and `claims` in vouch proxy: + +0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) +1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) + a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + b. log in and call the `/validate` endpoint in a modern browser + c. check the response header for a `X-Vouch-IdP-IdToken` header + d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider +2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` + a. log in and call the `/validate` endpoint in a modern browser + b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + c. If they are not there clear your cookies and cached browser data + d. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + e. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it +3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` + a. the syntax is `auth_request_set $ $upstream_http_;` + b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim +4. Consume the claim + a. Example: `proxy_set_header X-sub-claim $sub;` to pass the claim to a proxied backend server + + +
    +Nginx server config + +``` +server { + listen 80; + server_name localhost; + + location ^~ /sso/ { + location /sso/validate { + proxy_pass http://vouch:9090/validate; + proxy_set_header Host $http_host; + proxy_pass_request_body off; + } + + location = /sso/logout { + proxy_pass http://vouch:9090/logout?url=---------------------------------; + proxy_set_header Host $http_host; + } + + proxy_set_header Host $http_host; + proxy_pass http://vouch:9090/; + } + + location ^~ /api/v1/ { + auth_request /sso/validate; + # get the claim into an nginx variable + auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub; + + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # forward the claim to the proxied server + proxy_set_header X-sub-claim $sub; + proxy_redirect off; + proxy_buffering off; + proxy_pass http://api/; + } + + # uncomment this to forward static content of vouch-proxy + # used when running vouch-proxy with `testing: true` + # location /static/ { + # proxy_set_header Host $http_host; + # proxy_pass http://vouch:9090/static/; + #} + + location / { + auth_request /sso/validate; + + root /website; + index index.html; + + expires 0; + add_header Cache-Control "no-cache, no-store, must-revalidate, max-age=0"; + add_header Pragma "no-cache"; + } + + error_page 401 = @error401; + + location @error401 { + return 302 http://localhost/sso/login?url=$scheme://$http_host$request_uri; + } +} +``` + +
    + Please do help us to expand this list. All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) From 84ff9376888358bc1c3129e8fb47012ab1d92f2f Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:43:02 +0100 Subject: [PATCH 502/736] example nginx conf for claims --- README.md | 81 ++------------------- examples/nginx/nginx_scopes_and_claims.conf | 33 +++++++++ 2 files changed, 39 insertions(+), 75 deletions(-) create mode 100644 examples/nginx/nginx_scopes_and_claims.conf diff --git a/README.md b/README.md index 90084015..5ac83f70 100644 --- a/README.md +++ b/README.md @@ -218,11 +218,11 @@ Here is a protocol to set up `scopes` and `claims` in vouch proxy: 0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) - b. log in and call the `/validate` endpoint in a modern browser - c. check the response header for a `X-Vouch-IdP-IdToken` header - d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt - e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider + a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + b. log in and call the `/validate` endpoint in a modern browser + c. check the response header for a `X-Vouch-IdP-IdToken` header + d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` a. log in and call the `/validate` endpoint in a modern browser b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` @@ -232,78 +232,9 @@ Here is a protocol to set up `scopes` and `claims` in vouch proxy: 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` a. the syntax is `auth_request_set $ $upstream_http_;` b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim -4. Consume the claim - a. Example: `proxy_set_header X-sub-claim $sub;` to pass the claim to a proxied backend server +4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) -
    -Nginx server config - -``` -server { - listen 80; - server_name localhost; - - location ^~ /sso/ { - location /sso/validate { - proxy_pass http://vouch:9090/validate; - proxy_set_header Host $http_host; - proxy_pass_request_body off; - } - - location = /sso/logout { - proxy_pass http://vouch:9090/logout?url=---------------------------------; - proxy_set_header Host $http_host; - } - - proxy_set_header Host $http_host; - proxy_pass http://vouch:9090/; - } - - location ^~ /api/v1/ { - auth_request /sso/validate; - # get the claim into an nginx variable - auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub; - - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # forward the claim to the proxied server - proxy_set_header X-sub-claim $sub; - proxy_redirect off; - proxy_buffering off; - proxy_pass http://api/; - } - - # uncomment this to forward static content of vouch-proxy - # used when running vouch-proxy with `testing: true` - # location /static/ { - # proxy_set_header Host $http_host; - # proxy_pass http://vouch:9090/static/; - #} - - location / { - auth_request /sso/validate; - - root /website; - index index.html; - - expires 0; - add_header Cache-Control "no-cache, no-store, must-revalidate, max-age=0"; - add_header Pragma "no-cache"; - } - - error_page 401 = @error401; - - location @error401 { - return 302 http://localhost/sso/login?url=$scheme://$http_host$request_uri; - } -} -``` - -
    - Please do help us to expand this list. All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) diff --git a/examples/nginx/nginx_scopes_and_claims.conf b/examples/nginx/nginx_scopes_and_claims.conf new file mode 100644 index 00000000..5681000f --- /dev/null +++ b/examples/nginx/nginx_scopes_and_claims.conf @@ -0,0 +1,33 @@ +server { + listen 80; + server_name mydomain.com; + + location ^~ /sso/validate { + proxy_pass http://vouch:9090/validate; + proxy_set_header Host $http_host; + proxy_pass_request_body off; + } + + location ^~ /api/v1/ { + auth_request /sso/validate; + + # get the claim/s into a local nginx variable + auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub; + auth_request_set $email $upstream_http_x_vouch_idp_claims_email; + auth_request_set $verified $upstream_http_x_vouch_idp_claims_email_verified; + + # forward the claim to the proxied server + proxy_set_header X-sub $sub; + proxy_set_header X-email $email; + proxy_set_header X-email-verified $verified; + + # generic proxy headers + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_redirect off; + proxy_buffering off; + proxy_pass http://api./; + } +} \ No newline at end of file From 53d7ea6d8f7485d957a02a2d41f8f26d69f91f67 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:44:31 +0100 Subject: [PATCH 503/736] testing sub-list item formatting --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ac83f70..6eb972d6 100644 --- a/README.md +++ b/README.md @@ -211,12 +211,13 @@ With vouch-proxy you can request various `scopes` (standard and custom) to obtai Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -Warning: Userinfo will get added to the Vouch cookie and (possibly) make it large. The Vouch cookie may get split up into several cookies, but if you need it, you need it. +⚠️ **Userinfo will get added to the Vouch cookie and (possibly) make it large** ⚠️ + +The Vouch cookie may get split up into several cookies, but if you need it, you need it. With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. Here is a protocol to set up `scopes` and `claims` in vouch proxy: -0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) b. log in and call the `/validate` endpoint in a modern browser From 7548ec439a4c1e645f70ee717e9c68e7ceed1378 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:46:20 +0100 Subject: [PATCH 504/736] test alignment of warning --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6eb972d6..55c2040c 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ With vouch-proxy you can request various `scopes` (standard and custom) to obtai Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -⚠️ **Userinfo will get added to the Vouch cookie and (possibly) make it large** ⚠️ +

    ⚠️ Userinfo will get added to the Vouch cookie and (possibly) make it large ⚠️

    The Vouch cookie may get split up into several cookies, but if you need it, you need it. With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. From fce8def63cd24a3e8e5aeab7a7a834d5e01b7b93 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:48:30 +0100 Subject: [PATCH 505/736] getting nesting to work take 3 --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 55c2040c..87e2b477 100644 --- a/README.md +++ b/README.md @@ -218,21 +218,22 @@ With large cookies and headers it will require additional nginx config to open u Here is a protocol to set up `scopes` and `claims` in vouch proxy: +0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) - b. log in and call the `/validate` endpoint in a modern browser - c. check the response header for a `X-Vouch-IdP-IdToken` header - d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt - e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider + a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + b. log in and call the `/validate` endpoint in a modern browser + c. check the response header for a `X-Vouch-IdP-IdToken` header + d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` - a. log in and call the `/validate` endpoint in a modern browser - b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` - c. If they are not there clear your cookies and cached browser data - d. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug - e. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it + a. log in and call the `/validate` endpoint in a modern browser + b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + c. If they are not there clear your cookies and cached browser data + d. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + e. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` - a. the syntax is `auth_request_set $ $upstream_http_;` - b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim + a. the syntax is `auth_request_set $ $upstream_http_;` + b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) From 8413d760f42ec7c961fea4d1f6bafa1baa08e7aa Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 16:49:22 +0100 Subject: [PATCH 506/736] take 4 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 87e2b477..ec3a2da7 100644 --- a/README.md +++ b/README.md @@ -219,21 +219,25 @@ With large cookies and headers it will require additional nginx config to open u Here is a protocol to set up `scopes` and `claims` in vouch proxy: 0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) + 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) b. log in and call the `/validate` endpoint in a modern browser c. check the response header for a `X-Vouch-IdP-IdToken` header d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider + 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` a. log in and call the `/validate` endpoint in a modern browser b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` c. If they are not there clear your cookies and cached browser data d. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug e. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it + 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` a. the syntax is `auth_request_set $ $upstream_http_;` b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim + 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) From 923de49983585c31a4e1fc3a86b49a0c1e2bd9f4 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 17:00:32 +0100 Subject: [PATCH 507/736] change a-d numbering to 1-4 --- README.md | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ec3a2da7..7ee21b36 100644 --- a/README.md +++ b/README.md @@ -221,23 +221,20 @@ Here is a protocol to set up `scopes` and `claims` in vouch proxy: 0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - a. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) - b. log in and call the `/validate` endpoint in a modern browser - c. check the response header for a `X-Vouch-IdP-IdToken` header - d. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt - e. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider - + 1. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + 2. log in and call the `/validate` endpoint in a modern browser + 3. check the response header for a `X-Vouch-IdP-IdToken` header + 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` - a. log in and call the `/validate` endpoint in a modern browser - b. check the response headers for headers of the form `X-Vouch-Idp-Claims-` - c. If they are not there clear your cookies and cached browser data - d. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug - e. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it - + 1. log in and call the `/validate` endpoint in a modern browser + 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + 3. If they are not there clear your cookies and cached browser data + 4. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` - a. the syntax is `auth_request_set $ $upstream_http_;` - b. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim - + 1. the syntax is `auth_request_set $ $upstream_http_;` + 2. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) From ca56b08f04e4d0d7b830961d79e8d09e3656d687 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 18:18:45 +0100 Subject: [PATCH 508/736] still not rendering properly on GitHub --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7ee21b36..dfe963bf 100644 --- a/README.md +++ b/README.md @@ -221,20 +221,20 @@ Here is a protocol to set up `scopes` and `claims` in vouch proxy: 0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - 1. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) - 2. log in and call the `/validate` endpoint in a modern browser - 3. check the response header for a `X-Vouch-IdP-IdToken` header - 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt - 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider + 1. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + 2. log in and call the `/validate` endpoint in a modern browser + 3. check the response header for a `X-Vouch-IdP-IdToken` header + 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` - 1. log in and call the `/validate` endpoint in a modern browser - 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` - 3. If they are not there clear your cookies and cached browser data - 4. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug - 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it + 1. log in and call the `/validate` endpoint in a modern browser + 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + 3. If they are not there clear your cookies and cached browser data + 4. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` - 1. the syntax is `auth_request_set $ $upstream_http_;` - 2. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim + 1. the syntax is `auth_request_set $ $upstream_http_;` + 2. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) From db6980beab995d131a75804e08b68bd046a94429 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 18:24:07 +0100 Subject: [PATCH 509/736] some styling --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dfe963bf..ef707a26 100644 --- a/README.md +++ b/README.md @@ -216,25 +216,23 @@ extracted and stored in the vouch cookie. The Vouch cookie may get split up into several cookies, but if you need it, you need it. With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. -Here is a protocol to set up `scopes` and `claims` in vouch proxy: +Here is a protocol to set up `scopes` and `claims` in vouch proxy with nginx: 0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - 1. (temporarily) set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` (this will forward the jwt from the oauth provider as a response header) + 1. set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` 2. log in and call the `/validate` endpoint in a modern browser 3. check the response header for a `X-Vouch-IdP-IdToken` header 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` 1. log in and call the `/validate` endpoint in a modern browser - 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` 3. If they are not there clear your cookies and cached browser data - 4. If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + 4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it -3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx `server.conf` - 1. the syntax is `auth_request_set $ $upstream_http_;` - 2. Example: `auth_request_set $sub $upstream_http_x_vouch_idp_claims_sub;` for the `sub` claim +3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx [`server.conf`](examples/nginx/nginx_scopes_and_claims.conf) 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) From 5b82d7b2641cf1932ae666116f02b9f5ef6e12a0 Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 18:25:02 +0100 Subject: [PATCH 510/736] more styling --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef707a26..f7ceb5f3 100644 --- a/README.md +++ b/README.md @@ -205,13 +205,13 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) -#### Scopes and Claims +### Scopes and Claims With vouch-proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -

    ⚠️ Userinfo will get added to the Vouch cookie and (possibly) make it large ⚠️

    +

    ⚠️ **Userinfo will get added to the Vouch cookie and (possibly) make it large** ⚠️

    The Vouch cookie may get split up into several cookies, but if you need it, you need it. With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. From 9dc4465759821a1ba571346667359cade53abb3d Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 18:25:59 +0100 Subject: [PATCH 511/736] make warning bold --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7ceb5f3..557973bf 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ With vouch-proxy you can request various `scopes` (standard and custom) to obtai Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -

    ⚠️ **Userinfo will get added to the Vouch cookie and (possibly) make it large** ⚠️

    +

    ⚠️ Userinfo will get added to the Vouch cookie and (possibly) make it large ⚠️

    The Vouch cookie may get split up into several cookies, but if you need it, you need it. With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. From ca728df56f8e58a98558170f1c5316ff5b9a2cef Mon Sep 17 00:00:00 2001 From: FirefoxMetzger Date: Fri, 11 Dec 2020 18:27:15 +0100 Subject: [PATCH 512/736] reorganize paragraphs --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 557973bf..73ae75f7 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,8 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con ## More advanced configurations +All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) + - [cacheing of the Vouch Proxy validation response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) - [handleing `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) - [validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) @@ -205,6 +207,8 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) +Please do help us to expand this list. + ### Scopes and Claims With vouch-proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. @@ -236,10 +240,6 @@ Here is a protocol to set up `scopes` and `claims` in vouch proxy with nginx: 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) -Please do help us to expand this list. - -All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) - ## Running from Docker ```bash From 46c8a841cca269be02e3727ab9ae40914b8cd0f2 Mon Sep 17 00:00:00 2001 From: Bill ONeill Date: Tue, 15 Dec 2020 10:04:20 -0500 Subject: [PATCH 513/736] Update systemd configs to start at boot time --- examples/startup/systemd/vouch-proxy.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/startup/systemd/vouch-proxy.service b/examples/startup/systemd/vouch-proxy.service index 2824f748..406aaca6 100644 --- a/examples/startup/systemd/vouch-proxy.service +++ b/examples/startup/systemd/vouch-proxy.service @@ -1,6 +1,6 @@ [Unit] Description=Vouch Proxy -After=vouch-proxy.service +After=network.target [Service] Type=simple @@ -13,4 +13,4 @@ StartLimitInterval=60s StartLimitBurst=3 [Install] -WantedBy=default.target \ No newline at end of file +WantedBy=multi-user.target From 184dcfec161060b5d478d1bec8d2ada9adf16530 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 18 Dec 2020 13:56:51 -0800 Subject: [PATCH 514/736] #343 use default --- examples/startup/systemd/vouch-proxy.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/startup/systemd/vouch-proxy.service b/examples/startup/systemd/vouch-proxy.service index 406aaca6..e90be1c6 100644 --- a/examples/startup/systemd/vouch-proxy.service +++ b/examples/startup/systemd/vouch-proxy.service @@ -13,4 +13,4 @@ StartLimitInterval=60s StartLimitBurst=3 [Install] -WantedBy=multi-user.target +WantedBy=default.target \ No newline at end of file From 93e1487e4fa06c8902cde648b9f235a6f7d644ee Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 18 Dec 2020 14:52:38 -0800 Subject: [PATCH 515/736] #341 minor updates for clarity --- README.md | 113 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 73ae75f7..7233c8c9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. -Vouch Proxy supports many OAuth login providers and can enforce authentication to... +Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... - Google - [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) @@ -31,28 +31,28 @@ Please do let us know when you have deployed Vouch Proxy with your preffered IdP If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be less than 1ms --- + ## Table of Contents -* [What Vouch Proxy Does...](#what-vouch-proxy-does) -* [Installation and Configuration](#installation-and-configuration) -* [Configuring Vouch Proxy using Environmental Variables](#configuring-vouch-proxy-using-environmental-variables) -* [More advanced configurations](#more-advanced-configurations) - + [Scopes and Claims](#scopes-and-claims) -* [Running from Docker](#running-from-docker) -* [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) -* [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) -* [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) -* [Troubleshooting, Support and Feature Requests](#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) - (Read this before submitting an issue at GitHub) - + [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) - + [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) - + [submitting a Pull Request for a new feature](#submitting-a-pull-request-for-a-new-feature) -* [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) -* [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) +- [What Vouch Proxy Does...](#what-vouch-proxy-does) +- [Installation and Configuration](#installation-and-configuration) +- [Configuring Vouch Proxy using Environmental Variables](#configuring-vouch-proxy-using-environmental-variables) +- [More advanced configurations](#more-advanced-configurations) + - [Scopes and Claims](#scopes-and-claims) +- [Running from Docker](#running-from-docker) +- [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) +- [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) +- [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) +- [Troubleshooting, Support and Feature Requests](#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) + (Read this before submitting an issue at GitHub) + - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) + - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) + - [submitting a Pull Request for a new feature](#submitting-a-pull-request-for-a-new-feature) +- [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) +- [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) --- - ## What Vouch Proxy Does... Vouch Proxy (VP) forces visitors to login and authenticate with an [IdP](https://en.wikipedia.org/wiki/Identity_provider) (such as one of the services listed above) before allowing them access to a website. @@ -211,35 +211,31 @@ Please do help us to expand this list. ### Scopes and Claims -With vouch-proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. -Internally, vouch-proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are -extracted and stored in the vouch cookie. +With Vouch Proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -

    ⚠️ Userinfo will get added to the Vouch cookie and (possibly) make it large ⚠️

    +

    ⚠️ Additional claims and tokens are added to the VP cookie and can make it large ⚠️

    -The Vouch cookie may get split up into several cookies, but if you need it, you need it. -With large cookies and headers it will require additional nginx config to open up the buffers a bit. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. +The VP cookie may get split up into several cookies, but if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. -Here is a protocol to set up `scopes` and `claims` in vouch proxy with nginx: +#### Setup `scopes` and `claims` in Vouch Proxy with Nginx -0. Setup basic authentication (See: [Installation and Configuration](#installation-and-configuration)) +0. Configure Vouch Proxy for Nginx and your IdP as normal (See: [Installation and Configuration](#installation-and-configuration)) 1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) - 1. set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` - 2. log in and call the `/validate` endpoint in a modern browser - 3. check the response header for a `X-Vouch-IdP-IdToken` header - 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt - 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider + 1. set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` + 2. log in and call the `/validate` endpoint in a modern browser + 3. check the response header for a `X-Vouch-IdP-IdToken` header + 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` - 1. log in and call the `/validate` endpoint in a modern browser - 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` - 3. If they are not there clear your cookies and cached browser data - 4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug - 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it + 1. log in and call the `/validate` endpoint in a modern browser + 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + 3. If they are not there clear your cookies and cached browser data + 4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug + 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it 3. Use `auth_request_set` after `auth_request` inside the protected location in the nginx [`server.conf`](examples/nginx/nginx_scopes_and_claims.conf) 4. Consume the claim ([example nginx config](examples/nginx/nginx_scopes_and_claims.conf)) - ## Running from Docker ```bash @@ -274,7 +270,7 @@ Automated container builds for each Vouch Proxy release are available from [Dock ## Kubernetes Nginx Ingress -If you are using kubernetes with [nginx-ingress](https://github.com/kubernetes/ingress-nginx), you can configure your ingress with the following annotations (note quoting the auth-signin annotation): +If you are using kubernetes with [nginx-ingress](https://github.com/kubernetes/ingress-nginx), you can configure your ingress with the following annotations (note quoting the `auth-signin` annotation): ```bash nginx.ingress.kubernetes.io/auth-signin: "https://vouch.yourdomain.com/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err" @@ -299,7 +295,7 @@ Helm Charts are maintained by [halkeye](https://github.com/halkeye) and are avai ## /login and /logout endpoint redirection -As of `v0.11.0` we have put additional checks in place to reduce [the attack surface of url redirection](https://blog.detectify.com/2019/05/16/the-real-impact-of-an-open-redirect/). +As of `v0.11.0` additional checks are in place to reduce [the attack surface of url redirection](https://blog.detectify.com/2019/05/16/the-real-impact-of-an-open-redirect/). ### /login?url=POST_LOGIN_URL @@ -375,11 +371,26 @@ If you continue to have trouble, try the following: Please [submit a new issue](https://github.com/vouch/vouch-proxy/issues) in the following fashion.. +TLDR: + +- set `vouch.testing: true` +- set `vouch.logLevel: debug` +- conduct a full round trip of `./vouch-proxy` capturing the output.. + - VP startup + - `/validate` + - `/login` - even if the error is here + - `/auth` + - `/validate` - capture everything +- put all your logs and config in a `gist`. +- `./do.sh bug_report` is your friend + +#### But read this anyways because we'll ask you to read it if you don't follow these instruction. :) + - **turn on `vouch.testing: true`** and set `vouch.logLevel: debug`. -- use [hasteb.in](https://hasteb.in/), or another **paste service** or a [gist](https://gist.github.com/) to provide your logs and config. **_DO NOT PUT YOUR LOGS AND CONFIG INTO THE GITHUB ISSUE_**. Using a paste service is important as it will maintain spacing and will provide line numbers and formatting. We are hunting for needles in haystacks with setups with several moving parts, these features help considerably. Paste services save your time and our time and help us to help you quickly. You're more likely to get good support from us in a timely manner by following this advice. -- run `./do.sh bug_report yourdomain.com [yourotherdomain.com]` which will create a redacted version of your config and logs +- use a [gist](https://gist.github.com/) or another **paste service** such as [hasteb.in](https://hasteb.in/). **_DO NOT PUT YOUR LOGS AND CONFIG INTO THE GITHUB ISSUE_**. Using a paste service is important as it will maintain spacing and will provide line numbers and formatting. We are hunting for needles in haystacks with setups with several moving parts, these features help considerably. Paste services save your time and our time and help us to help you quickly. You're more likely to get good support from us in a timely manner by following this advice. +- run `./do.sh bug_report secretdomain.com secretpass [anothersecret..]` which will create a redacted version of your config and logs removing each of those strings - and follow the instructions at the end to redact your Nginx config -- all of those go into [hasteb.in](https://hasteb.in/) or a [gist](https://gist.github.com/) +- all of those go into a [gist](https://gist.github.com/) - then [open a new issue](https://github.com/vouch/vouch-proxy/issues/new) in this repository - or visit our IRC channel [#vouch](irc://freenode.net/#vouch) on freenode @@ -421,21 +432,21 @@ OpenResty and configs for a variety of scenarios are available in the [examples] - 401 NotAuthorized then - respond to Bob with a 302 redirect to `https://vouch.oursites.com/login?url=https://private.oursites.com` -- vouch `https://vouch.oursites.com/validate` +- Vouch Proxy `https://vouch.oursites.com/validate` - recieves the request for private.oursites.com from Bob via Nginx `proxy_pass` - - it looks for a cookie named "oursitesSSO" that contains a JWT + - looks for a cookie named "oursitesSSO" that contains a JWT - if the cookie is found, and the JWT is valid - - returns 200 to Nginx, which will allow access (bob notices nothing) + - returns `200 OK` to Nginx, which will allow access (bob notices nothing) - if the cookie is NOT found, or the JWT is NOT valid - - return 401 NotAuthorized to Nginx (which forwards the request on to login) + - return `401 NotAuthorized` to Nginx (which forwards the request on to login) - Bob is first forwarded briefly to `https://vouch.oursites.com/login?url=https://private.oursites.com` - clears out the cookie named "oursitesSSO" if it exists - generates a nonce and stores it in session variable \$STATE - - stores the url `https://private.oursites.com` from the query string in session variable \$requestedURL - - respond to Bob with a 302 redirect to Google's OAuth Login form, including the \$STATE nonce + - stores the url `https://private.oursites.com` from the query string in session variable `$requestedURL` + - respond to Bob with a 302 redirect to Google's OAuth Login form, including the `$STATE` nonce - Bob logs into his Google account using Oauth @@ -444,13 +455,13 @@ OpenResty and configs for a variety of scenarios are available in the [examples] - Bob is forwarded to `https://vouch.oursites.com/auth?state=$STATE` - if the \$STATE nonce from the url matches the session variable "state" - - make a "third leg" request of google (server to server) to exchange the OAuth code for Bob's user info including email address bob@oursites.com + - make a "third leg" request of Google (server to server) to exchange the OAuth code for Bob's user info including email address bob@oursites.com - if the email address matches the domain oursites.com (it does) - issue bob a JWT in the form of a cookie named "oursitesSSO" - - retrieve the session variable $requestedURL and 302 redirect bob back to $requestedURL + - retrieve the session variable `$requestedURL` and 302 redirect bob back to `https://private.oursites.com` Note that outside of some innocuos redirection, Bob only ever sees `https://private.oursites.com` and the Google Login screen in his browser. While Vouch does interact with Bob's browser several times, it is just to set cookies, and if the 302 redirects work properly Bob will log in quickly. Once the JWT is set, Bob will be authorized for all other sites which are configured to use `https://vouch.oursites.com/validate` from the `auth_request` Nginx module. -The next time Bob is forwarded to google for login, since he has already authorized the Vouch OAuth app, Google immediately forwards him back and sets the cookie and sends him on his merry way. Bob may not even notice that he logged in via Vouch. +The next time Bob is forwarded to google for login, since he has already authorized the Vouch Proxy OAuth app, Google immediately forwards him back and sets the cookie and sends him on his merry way. In some browsers such as Chrome, Bob may not even notice that he logged in using Vouch Proxy. From 82bb2a66ddaf0cc57cbb25c9f51d38a4343c633b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 18 Dec 2020 15:21:57 -0800 Subject: [PATCH 516/736] #341 change example config file name --- ...and_claims_config.yml => config.yml_example_scopes_and_claims} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/{scopes_and_claims_config.yml => config.yml_example_scopes_and_claims} (100%) diff --git a/config/scopes_and_claims_config.yml b/config/config.yml_example_scopes_and_claims similarity index 100% rename from config/scopes_and_claims_config.yml rename to config/config.yml_example_scopes_and_claims From 3a5b29ff7cd7b450cd9a590b9e9bed18da714eef Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 18 Dec 2020 15:25:43 -0800 Subject: [PATCH 517/736] #341 adjust scopes_and_claims file name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7233c8c9..abe0267a 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ Please do help us to expand this list. With Vouch Proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. -

    ⚠️ Additional claims and tokens are added to the VP cookie and can make it large ⚠️

    +⚠️ **Additional claims and tokens will be added to the VP cookie and can make it large** The VP cookie may get split up into several cookies, but if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. @@ -221,7 +221,7 @@ The VP cookie may get split up into several cookies, but if you need it, you nee 0. Configure Vouch Proxy for Nginx and your IdP as normal (See: [Installation and Configuration](#installation-and-configuration)) -1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/scopes_and_claims_config.yml)) +1. Set the necessary `scope`s in the `oauth` section of the vouch-proxy `config.yml` ([example config](config/config.yml_example_scopes_and_claims)) 1. set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` 2. log in and call the `/validate` endpoint in a modern browser 3. check the response header for a `X-Vouch-IdP-IdToken` header From 9052f7e4a2c3b1be20de075c5e302faca5c21043 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 29 Dec 2020 08:50:25 -0800 Subject: [PATCH 518/736] prefer gist for bug_report --- do.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/do.sh b/do.sh index 3159000d..12c404d9 100755 --- a/do.sh +++ b/do.sh @@ -121,11 +121,12 @@ EOF } + _redact_exit () { echo -e "\n\n-------------------------\n" echo -e "redact your nginx config with:\n" echo -e "\tcat nginx.conf | sed 's/yourdomain.com/DOMAIN.COM/g'\n" - echo -e "Please upload both configs and some logs to https://hastebin.com/ and open an issue on GitHub at https://github.com/vouch/vouch-proxy/issues\n" + echo -e "Please upload configs and logs to a gist and open an issue on GitHub at https://github.com/vouch/vouch-proxy/issues\n" } _redact() { From 4fe43a232ecec05bd223586f9edfc9029a5ed1a8 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 13 Jan 2021 12:41:17 -0800 Subject: [PATCH 519/736] run `do.sh bug_report` in alpine docker container --- .dockerignore | 2 ++ .gitignore | 1 + Dockerfile.alpine | 9 +++++---- README.md | 6 ++++++ do.sh | 5 +++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.dockerignore b/.dockerignore index 10309e91..b06a2ee6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,3 +11,5 @@ config/config.yml_orig .dockerignore Dockerfile handlers/rice-box.go +certs +.cover/* diff --git a/.gitignore b/.gitignore index 69943ee8..465ee477 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ certs/* coverage.out coverage.html.env_google .env* +.cover diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 0bf757b7..bf0c12dc 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -9,22 +9,23 @@ WORKDIR ${GOPATH}/src/github.com/vouch/vouch-proxy COPY . . -# RUN go-wrapper download # "go get -d -v ./..." -# RUN ./do.sh build # see `do.sh` for vouch build details -# RUN go-wrapper install # "go install -v ./..." - RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details RUN ./do.sh install FROM alpine:latest LABEL maintainer="vouch@bnf.net" +ENV VOUCH_ROOT=/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY templates/ templates/ COPY .defaults.yml .defaults.yml # see note for /static in main.go COPY static /static + +# do.sh requires bash +RUN apk add --no-cache bash COPY do.sh /do.sh + COPY --from=builder /go/bin/vouch-proxy /vouch-proxy EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/README.md b/README.md index abe0267a..89442485 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,12 @@ TLDR: - then [open a new issue](https://github.com/vouch/vouch-proxy/issues/new) in this repository - or visit our IRC channel [#vouch](irc://freenode.net/#vouch) on freenode +A bug report can be generated from a docker environment using the `voucher/vouch-proxy:alpine` image... + +```!bash +docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh voucher/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret +``` + ### submitting a Pull Request for a new feature I really love Vouch Proxy! I wish it did XXXX... diff --git a/do.sh b/do.sh index 12c404d9..093dad2a 100755 --- a/do.sh +++ b/do.sh @@ -7,7 +7,9 @@ SCRIPT=$(readlink -f "$0") SDIR=$(dirname "$SCRIPT") cd $SDIR -export VOUCH_ROOT=${GOPATH}/src/github.com/vouch/vouch-proxy/ +if [ -z "$VOUCH_ROOT" ]; then + export VOUCH_ROOT=${GOPATH}/src/github.com/vouch/vouch-proxy/ +fi IMAGE=voucher/vouch-proxy:latest ALPINE=voucher/vouch-proxy:alpine @@ -119,7 +121,6 @@ EOF trap _redact_exit SIGINT ./vouch-proxy 2>&1 | _redact - } _redact_exit () { From 498a197ccbb3a71b7adf25e0af19ce405c617194 Mon Sep 17 00:00:00 2001 From: gsx95 Date: Tue, 12 Jan 2021 23:03:32 +0100 Subject: [PATCH 520/736] add support for multiple login states in different tabs the session cookie that contains the state now has its path attribute set to /auth/[state]/. /auth redirects the user to this new endpoint, which will only receive the session that was set with this specific state. /auth/[state]/ will then perform the known authentication that was formerly done by /auth. This allows for multiple login tabs to be opened at the same time with all of them still working. --- handlers/auth.go | 36 +++++++++++++++++++++--------------- handlers/login.go | 5 +++++ main.go | 3 +++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index 48668d50..8984e215 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -11,29 +11,38 @@ OR CONDITIONS OF ANY KIND, either express or implied. package handlers import ( - "errors" "fmt" - "golang.org/x/oauth2" - "net/http" - "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/domains" "github.com/vouch/vouch-proxy/pkg/jwtmanager" - "github.com/vouch/vouch-proxy/pkg/responses" "github.com/vouch/vouch-proxy/pkg/structs" -) + "golang.org/x/oauth2" + "net/http" -var ( - errSessionNotFound = errors.New("/auth could not retrieve session") - errInvalidState = errors.New("/auth the state nonce returned by the IdP does not match the value stored in the session") - errURLNotFound = errors.New("/auth could not retrieve URL from session") + "github.com/vouch/vouch-proxy/pkg/responses" ) // CallbackHandler /auth +// - redirects to /auth/{state}/ with the state coming from the query parameter +func CallbackHandler(w http.ResponseWriter, r *http.Request) { + log.Debug("/auth") + + queryState := r.URL.Query().Get("state") + if queryState == "" { + responses.Error400(w, r, fmt.Errorf("/auth: could not find state in query %s", r.URL.RawQuery)) + return + } + // has to have a trailing / in its path, because the path of the session cookie is set to /auth/{state}/. + authStateURL := fmt.Sprintf("/auth/%s/?%s", queryState, r.URL.RawQuery) + responses.Redirect302(w, r, authStateURL) + +} + +// AuthStateHandler /auth/{state} // - validate info from oauth provider (Google, GitHub, OIDC, etc) // - issue jwt in the form of a cookie -func CallbackHandler(w http.ResponseWriter, r *http.Request) { +func AuthStateHandler(w http.ResponseWriter, r *http.Request) { log.Debug("/auth") // Handle the exchange code to initiate a transport. @@ -50,7 +59,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { return } - // did the IdP return an error when they redirected back to /auth + // did the IdP return an error? errorIDP := r.URL.Query().Get("error") if errorIDP != "" { errorDescription := r.URL.Query().Get("error_description") @@ -77,9 +86,6 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { return } log.Debugf("/auth Claims from userinfo: %+v", customClaims) - //getProviderJWT(r, &user) - // log.Debug("/auth CallbackHandler") - // log.Debugf("/auth %+v", user) // verify / authz the user if ok, err := verifyUser(user); !ok { diff --git a/handlers/login.go b/handlers/login.go index bcbfc148..3ed34776 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -52,6 +52,11 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // set the state variable in the session session.Values["state"] = state + + // set the path for the session cookie to only send the correct cookie to /auth/{state}/ + // must have a trailing slash. Otherwise, it is send to all endpoints that _start_ with the cookie path. + session.Options.Path = fmt.Sprintf("/auth/%s/", state) + log.Debugf("session state set to %s", session.Values["state"]) // requestedURL comes from nginx in the query string via a 302 redirect diff --git a/main.go b/main.go index d6face4b..d7314f82 100644 --- a/main.go +++ b/main.go @@ -141,6 +141,9 @@ func main() { logoutH := http.HandlerFunc(handlers.LogoutHandler) muxR.HandleFunc("/logout", timelog.TimeLog(logoutH)) + authStateH := http.HandlerFunc(handlers.AuthStateHandler) + muxR.HandleFunc("/auth/{state}/", timelog.TimeLog(authStateH)) + callH := http.HandlerFunc(handlers.CallbackHandler) muxR.HandleFunc("/auth", timelog.TimeLog(callH)) From 4b5acc330c0ada88f5ca9d9ed068c29dad969df4 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 20 Jan 2021 17:32:18 -0800 Subject: [PATCH 521/736] #349 handle any error from the IdP early --- handlers/auth.go | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index 8984e215..3c2493b0 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -12,15 +12,16 @@ package handlers import ( "fmt" + "net/http" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/domains" "github.com/vouch/vouch-proxy/pkg/jwtmanager" + "github.com/vouch/vouch-proxy/pkg/responses" "github.com/vouch/vouch-proxy/pkg/structs" - "golang.org/x/oauth2" - "net/http" - "github.com/vouch/vouch-proxy/pkg/responses" + "golang.org/x/oauth2" ) // CallbackHandler /auth @@ -28,6 +29,14 @@ import ( func CallbackHandler(w http.ResponseWriter, r *http.Request) { log.Debug("/auth") + // did the IdP return an error? + errorIDP := r.URL.Query().Get("error") + if errorIDP != "" { + errorDescription := r.URL.Query().Get("error_description") + responses.Error401(w, r, fmt.Errorf("/auth Error from IdP: %s - %s", errorIDP, errorDescription)) + return + } + queryState := r.URL.Query().Get("state") if queryState == "" { responses.Error400(w, r, fmt.Errorf("/auth: could not find state in query %s", r.URL.RawQuery)) @@ -39,11 +48,11 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { } -// AuthStateHandler /auth/{state} +// AuthStateHandler /auth/{state}/ // - validate info from oauth provider (Google, GitHub, OIDC, etc) // - issue jwt in the form of a cookie func AuthStateHandler(w http.ResponseWriter, r *http.Request) { - log.Debug("/auth") + log.Debug("/auth/{state}/") // Handle the exchange code to initiate a transport. session, err := sessstore.Get(r, cfg.Cfg.Session.Name) @@ -59,14 +68,6 @@ func AuthStateHandler(w http.ResponseWriter, r *http.Request) { return } - // did the IdP return an error? - errorIDP := r.URL.Query().Get("error") - if errorIDP != "" { - errorDescription := r.URL.Query().Get("error_description") - responses.Error401(w, r, fmt.Errorf("/auth Error from IdP: %s - %s", errorIDP, errorDescription)) - return - } - user := structs.User{} customClaims := structs.CustomClaims{} ptokens := structs.PTokens{} @@ -85,7 +86,7 @@ func AuthStateHandler(w http.ResponseWriter, r *http.Request) { responses.Error400(w, r, fmt.Errorf("/auth Error while retreiving user info after successful login at the OAuth provider: %w", err)) return } - log.Debugf("/auth Claims from userinfo: %+v", customClaims) + log.Debugf("/auth/{state}/ Claims from userinfo: %+v", customClaims) // verify / authz the user if ok, err := verifyUser(user); !ok { @@ -113,7 +114,8 @@ func AuthStateHandler(w http.ResponseWriter, r *http.Request) { responses.Redirect302(w, r, requestedURL) return } - // otherwise serve an error (why isn't there a ) + + // otherwise serve an error responses.RenderIndex(w, "/auth "+tokenstring) } From ad799d35f04e452796b514029fd5604c19a0280a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 20 Jan 2021 18:59:11 -0800 Subject: [PATCH 522/736] docker COPY into `/` --- Dockerfile | 4 ++-- Dockerfile.alpine | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index b2e346ca..9da63e31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,8 @@ RUN ./do.sh install FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY templates/ templates/ -COPY .defaults.yml .defaults.yml +COPY templates /templates +COPY .defaults.yml /.defaults.yml # see note for /static in main.go COPY static /static COPY --from=builder /go/bin/vouch-proxy /vouch-proxy diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 0bf757b7..c200981e 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -20,8 +20,8 @@ RUN ./do.sh install FROM alpine:latest LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY templates/ templates/ -COPY .defaults.yml .defaults.yml +COPY templates /templates +COPY .defaults.yml /.defaults.yml # see note for /static in main.go COPY static /static COPY do.sh /do.sh From c8234bb06f12158d008452de7efc031120b46ded Mon Sep 17 00:00:00 2001 From: PhiBo Date: Mon, 25 Jan 2021 09:07:21 +0100 Subject: [PATCH 523/736] Fix cookie.maxAge in config example If the value for cookie.maxAge is larger than for jwt.maxAge the value is set to jwt.maxAge. This has been implemented in #103 --- config/config.yml_example | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index dcbd707c..e9861d2b 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -92,8 +92,10 @@ vouch: # httpOnly: true # VOUCH_COOKIE_HTTPONLY - # Set cookie maxAge to 0 to delete the cookie every time the browser is closed. - VOUCH_COOKIE_MAXAGE - maxAge: 14400 + # Number of minutes until session cookie expires - VOUCH_COOKIE_MAXAGE + # Set cookie maxAge to 0 to delete the cookie every time the browser is closed. + # Must not longer than jwt.maxAge + maxAge: 240 # Set SameSite attribute to restrict browser behaviour wrt sending the cookie along with cross-site requests. - VOUCH_COOKIE_SAMESITE # Possible attribute values lax, strict, none. From 36709f61390c7d9e02e67f3bdafc79ab168d3b66 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 25 Jan 2021 18:31:22 -0800 Subject: [PATCH 524/736] #352 maxAge description --- config/config.yml_example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yml_example b/config/config.yml_example index e9861d2b..25b6b430 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -94,7 +94,7 @@ vouch: # Number of minutes until session cookie expires - VOUCH_COOKIE_MAXAGE # Set cookie maxAge to 0 to delete the cookie every time the browser is closed. - # Must not longer than jwt.maxAge + # Must not be longer than jwt.maxAge maxAge: 240 # Set SameSite attribute to restrict browser behaviour wrt sending the cookie along with cross-site requests. - VOUCH_COOKIE_SAMESITE From f72df9b49ea55a08c24293604808a893969ecc98 Mon Sep 17 00:00:00 2001 From: "whitesource-bolt-for-github[bot]" <42819689+whitesource-bolt-for-github[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 17:56:02 +0000 Subject: [PATCH 525/736] Add .whitesource configuration file --- .whitesource | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .whitesource diff --git a/.whitesource b/.whitesource new file mode 100644 index 00000000..55b922e8 --- /dev/null +++ b/.whitesource @@ -0,0 +1,12 @@ +{ + "scanSettings": { + "baseBranches": [] + }, + "checkRunSettings": { + "vulnerableCheckRunConclusionLevel": "failure", + "displayMode": "diff" + }, + "issueSettings": { + "minSeverityLevel": "LOW" + } +} \ No newline at end of file From 99e3fd93bfed01a4881c70e5c928277d85d5936f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 26 Jan 2021 12:21:08 -0800 Subject: [PATCH 526/736] #331 fix minor formatting warnings --- pkg/jwtmanager/jwtmanager.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 25ad7cf1..f2f144d7 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -81,12 +81,12 @@ func decryptionKey() (interface{}, error) { f, err := os.Open(cfg.Cfg.JWT.PublicKeyFile) if err != nil { - return nil, fmt.Errorf("error opening Key %s: %s\n", cfg.Cfg.JWT.PublicKeyFile, err) + return nil, fmt.Errorf("error opening Key %s: %s", cfg.Cfg.JWT.PublicKeyFile, err) } keyBytes, err := ioutil.ReadAll(f) if err != nil { - return nil, fmt.Errorf("error reading Key: %s\n", err) + return nil, fmt.Errorf("error reading Key: %s", err) } var key interface{} @@ -101,7 +101,7 @@ func decryptionKey() (interface{}, error) { } if err != nil { - return nil, fmt.Errorf("error parsing Key: %s\n", err) + return nil, fmt.Errorf("error parsing Key: %s", err) } return key, nil @@ -114,12 +114,12 @@ func signingKey() (interface{}, error) { f, err := os.Open(cfg.Cfg.JWT.PrivateKeyFile) if err != nil { - return nil, fmt.Errorf("error opening RSA Key %s: %s\n", cfg.Cfg.JWT.PrivateKeyFile, err) + return nil, fmt.Errorf("error opening RSA Key %s: %s", cfg.Cfg.JWT.PrivateKeyFile, err) } keyBytes, err := ioutil.ReadAll(f) if err != nil { - return nil, fmt.Errorf("error reading Key: %s\n", err) + return nil, fmt.Errorf("error reading Key: %s", err) } var key interface{} @@ -134,7 +134,7 @@ func signingKey() (interface{}, error) { } if err != nil { - return nil, fmt.Errorf("error parsing Key: %s\n", err) + return nil, fmt.Errorf("error parsing Key: %s", err) } return key, nil From e57c46394a3ea466dc56a0258ee4563d5804ccd2 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 26 Jan 2021 18:50:37 -0800 Subject: [PATCH 527/736] add github action coverage --- .github/workflows/coverage.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..7a659f1b --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,30 @@ +name: coverage + +on: + workflow_dispatch: + push: + pull_request: + +jobs: + cover: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v1 + with: + go-version: '1.15' + - uses: actions/checkout@v2 + - run: go test -v -coverprofile=.cover/cover.out ./... + + - name: Send coverage + uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: .cover/cover.out + + # notifies that all test jobs are finished. + # finish: + # needs: cover + # runs-on: ubuntu-latest + # steps: + # - uses: shogo82148/actions-goveralls@v1 + # with: + # parallel-finished: true \ No newline at end of file From b7a1cecebcf3119636d1721f6ed59acccc7ca847 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 26 Jan 2021 19:11:01 -0800 Subject: [PATCH 528/736] get packages --- .github/workflows/coverage.yml | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7a659f1b..8ced2bda 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,25 +6,33 @@ on: pull_request: jobs: - cover: + test: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + go: ['1.11', '1.12', '1.13', '1.14', '1.15'] + steps: - - uses: actions/setup-go@v1 + - uses: actions/setup-go@v2 with: - go-version: '1.15' + go-version: ${{ matrix.go }} - uses: actions/checkout@v2 + - run: ./do.sh goget - run: go test -v -coverprofile=.cover/cover.out ./... - name: Send coverage uses: shogo82148/actions-goveralls@v1 with: path-to-profile: .cover/cover.out + flag-name: Go-${{ matrix.go }} + parallel: true # notifies that all test jobs are finished. - # finish: - # needs: cover - # runs-on: ubuntu-latest - # steps: - # - uses: shogo82148/actions-goveralls@v1 - # with: - # parallel-finished: true \ No newline at end of file + finish: + needs: test + runs-on: ubuntu-latest + steps: + - uses: shogo82148/actions-goveralls@v1 + with: + parallel-finished: true \ No newline at end of file From 81640006d3c26f218feecaf3067cc41b030e0c28 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 09:26:02 -0800 Subject: [PATCH 529/736] set working-directory --- .github/workflows/coverage.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8ced2bda..d0fc856d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -7,19 +7,29 @@ on: jobs: test: + env: + GOPATH: ${{ github.workspace }} + defaults: + run: + working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: - go: ['1.11', '1.12', '1.13', '1.14', '1.15'] + go: ['1.12', '1.13', '1.14', '1.15'] steps: - uses: actions/setup-go@v2 with: go-version: ${{ matrix.go }} - - uses: actions/checkout@v2 - - run: ./do.sh goget - - run: go test -v -coverprofile=.cover/cover.out ./... + - name: checkout + uses: actions/checkout@v2 + with: + path: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} + - name: goget + run: ./do.sh goget + - name: coverage test + run: go test -v -coverprofile=.cover/cover.out ./... - name: Send coverage uses: shogo82148/actions-goveralls@v1 From 4a52f07896a981cdc5288224589599977b4a8f88 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 09:36:18 -0800 Subject: [PATCH 530/736] mkdir .cover --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d0fc856d..65acb745 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,7 +29,7 @@ jobs: - name: goget run: ./do.sh goget - name: coverage test - run: go test -v -coverprofile=.cover/cover.out ./... + run: mkdir .cover && go test -v -coverprofile=.cover/cover.out ./... - name: Send coverage uses: shogo82148/actions-goveralls@v1 From 2917f6c389bcb6e5d1347f77a8ba19d1b632babd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 09:45:06 -0800 Subject: [PATCH 531/736] set VOUCH_ROOT --- .github/workflows/coverage.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 65acb745..ff0636de 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -9,6 +9,7 @@ jobs: test: env: GOPATH: ${{ github.workspace }} + VOUCH_ROOT: ${{ github.workspace }}/src/github.com/${{ github.repository }} defaults: run: working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} @@ -16,7 +17,8 @@ jobs: strategy: fail-fast: false matrix: - go: ['1.12', '1.13', '1.14', '1.15'] + # go: ['1.12', '1.13', '1.14', '1.15'] + go: ['1.15'] steps: - uses: actions/setup-go@v2 From 8c7f6d29818960385c1680da1513db2749295084 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 09:59:26 -0800 Subject: [PATCH 532/736] set working-directory of coverage test --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ff0636de..af67c0d2 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -32,6 +32,7 @@ jobs: run: ./do.sh goget - name: coverage test run: mkdir .cover && go test -v -coverprofile=.cover/cover.out ./... + working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} - name: Send coverage uses: shogo82148/actions-goveralls@v1 From 80d8c23d0de0aedfeae115b41b3461a2062499e1 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 10:05:36 -0800 Subject: [PATCH 533/736] absolute path to .cover/cover.out --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index af67c0d2..9a345b38 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -37,7 +37,7 @@ jobs: - name: Send coverage uses: shogo82148/actions-goveralls@v1 with: - path-to-profile: .cover/cover.out + path-to-profile: ${{ env.GOPATH }}/src/github.com/${{ github.repository }}/.cover/cover.out flag-name: Go-${{ matrix.go }} parallel: true From 5abe0dcf859fdefb7df67b58ac41954c25b70614 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 10:35:46 -0800 Subject: [PATCH 534/736] use ./do.sh coverage --- .github/workflows/coverage.yml | 17 ++++++----- coverage_report.sh | 52 ---------------------------------- do.sh | 12 +++++--- 3 files changed, 16 insertions(+), 65 deletions(-) delete mode 100755 coverage_report.sh diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9a345b38..8955cc41 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -6,19 +6,19 @@ on: pull_request: jobs: - test: + coverage: env: GOPATH: ${{ github.workspace }} VOUCH_ROOT: ${{ github.workspace }}/src/github.com/${{ github.repository }} - defaults: - run: - working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} + # defaults: + # run: + # working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: - # go: ['1.12', '1.13', '1.14', '1.15'] - go: ['1.15'] + go: ['1.12', '1.13', '1.14', '1.15'] + # go: ['1.15'] steps: - uses: actions/setup-go@v2 @@ -31,8 +31,7 @@ jobs: - name: goget run: ./do.sh goget - name: coverage test - run: mkdir .cover && go test -v -coverprofile=.cover/cover.out ./... - working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} + run: ./do.sh coverage - name: Send coverage uses: shogo82148/actions-goveralls@v1 @@ -43,7 +42,7 @@ jobs: # notifies that all test jobs are finished. finish: - needs: test + needs: coverage runs-on: ubuntu-latest steps: - uses: shogo82148/actions-goveralls@v1 diff --git a/coverage_report.sh b/coverage_report.sh deleted file mode 100755 index 1d64f1fe..00000000 --- a/coverage_report.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# Generate test coverage statistics for Go packages. -# -# Works around the fact that `go test -coverprofile` currently does not work -# with multiple packages, see https://code.google.com/p/go/issues/detail?id=6909 -# -# Usage: script/coverage [--html|--coveralls] -# -# --html Additionally create HTML report and open it in browser -# --coveralls Push coverage statistics to coveralls.io -# - -set -e - -workdir=.cover -profile="$workdir/cover.out" -mode=count - -generate_cover_data() { - rm -rf "$workdir" - mkdir "$workdir" - - for pkg in "$@"; do - f="$workdir/$(echo $pkg | tr / -).cover" - go test -covermode="$mode" -coverprofile="$f" "$pkg" - done - - echo "mode: $mode" >"$profile" - grep -h -v "^mode:" "$workdir"/*.cover >>"$profile" -} - -show_cover_report() { - go tool cover -${1}="$profile" -} - -push_to_coveralls() { - echo "Pushing coverage statistics to coveralls.io" - goveralls -coverprofile="$profile" -} - -generate_cover_data $(go list ./...) -show_cover_report func -case "$1" in -"") - ;; ---html) - show_cover_report html ;; ---coveralls) - push_to_coveralls ;; -*) - echo >&2 "error: invalid option: $1"; exit 1 ;; -esac diff --git a/do.sh b/do.sh index 093dad2a..bb7f33df 100755 --- a/do.sh +++ b/do.sh @@ -148,9 +148,11 @@ _redact() { } coverage() { - export EXTRA_TEST_ARGS='-cover' - test - go tool cover -html=coverage.out -o coverage.html + mkdir -p .cover && go test -v -coverprofile=.cover/cover.out ./... +} + +coveragereport() { + go tool cover -html=.cover/cover.out -o .cover/coverage.html } test() { @@ -347,7 +349,8 @@ usage() { $0 drunalpine [args] - run docker container for alpine $0 test [./pkg_test.go] - run go tests (defaults to all tests) $0 test_logging - test the logging output - $0 coverage - coverage report + $0 coverage - coverage test + $0 coveragereport - coverage report published to .cover/coverage.html $0 profile - go pprof tools $0 bug_report domain.com - print config file removing secrets and each provided domain $0 gogo [gocmd] - run, build, any go cmd @@ -379,6 +382,7 @@ case "$ARG" in |'watch' \ |'gobuildstatic' \ |'coverage' \ + |'coveragereport' \ |'stats' \ |'usage' \ |'bug_report' \ From 6387204d7cd870e967fe39c8912ffbefd54ddde0 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 10:37:37 -0800 Subject: [PATCH 535/736] set working-directory --- .github/workflows/coverage.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8955cc41..34bebf6f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -10,9 +10,9 @@ jobs: env: GOPATH: ${{ github.workspace }} VOUCH_ROOT: ${{ github.workspace }}/src/github.com/${{ github.repository }} - # defaults: - # run: - # working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} + defaults: + run: + working-directory: ${{ env.GOPATH }}/src/github.com/${{ github.repository }} runs-on: ubuntu-latest strategy: fail-fast: false From 3ed968c66f21e5c5ce331d4037427d9fde2a261b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 10:41:46 -0800 Subject: [PATCH 536/736] support go 1.14 and 1.15, drop 1.12 and 1.13 --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 34bebf6f..29502615 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - go: ['1.12', '1.13', '1.14', '1.15'] + go: ['1.14', '1.15'] # go: ['1.15'] steps: From 6418e5210db63c5229f7b39de0510633b78d143f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 12:26:23 -0800 Subject: [PATCH 537/736] no change needed --- config/testing/test_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/testing/test_config.yml b/config/testing/test_config.yml index 3d72029b..8143b4f6 100644 --- a/config/testing/test_config.yml +++ b/config/testing/test_config.yml @@ -17,7 +17,7 @@ vouch: name: VouchTestingSession jwt: - secret: testingSecret + secret: testingsecret oauth: provider: indieauth From 53ed07afbb2f4bd235026837077f57531e9cd2eb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 12:26:43 -0800 Subject: [PATCH 538/736] #331 add env vars --- config/config.yml_example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index e9203154..126a2f23 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -62,7 +62,7 @@ vouch: profile: intermediate # VOUCH_TLS_PROFILE jwt: - # signing_method: the algorithm used to sign the JWT. + # signing_method: the algorithm used to sign the JWT. # VOUCH_JWT_SIGNING_METHOD # Can be one of HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512 # Default is HS256 (HMAC) - and requires jwt.secret to be set # Both RS* (RSA) and ES* (ECDSA) methods require jwt.private_key_file and @@ -80,8 +80,8 @@ vouch: secret: your_random_string # Path to the public/private key files when using an RSA or ECDSA signing method. - # public_key_file: - # private_key_file: + # public_key_file: # VOUCH_JWT_PUBLIC_KEY_FILE + # private_key_file: # VOUCH_JWT_PRIVATE_KEY_FILE # issuer: Vouch # VOUCH_JWT_ISSUER From d4264fef18f943b86f2b94d70164a9210a37c827 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 27 Jan 2021 12:42:48 -0800 Subject: [PATCH 539/736] #331 use .defaults.yml to set HS256 --- .defaults.yml | 1 + handlers/handlers_test.go | 12 ++++++------ pkg/cfg/cfg.go | 6 ------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index 468c1c07..55f74827 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -25,6 +25,7 @@ vouch: issuer: Vouch maxAge: 240 compress: true + signing_method: HS256 cookie: name: VouchCookie diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 6a968940..d1ff237f 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -141,12 +141,12 @@ func init() { // log.SetLevel(log.DebugLevel) lc = jwtmanager.VouchClaims{ - u1.Username, - jwtmanager.Sites, - customClaims.Claims, - t1.PAccessToken, - t1.PIdToken, - jwtmanager.StandardClaims, + Username: u1.Username, + Sites: jwtmanager.Sites, + CustomClaims: customClaims.Claims, + PAccessToken: t1.PAccessToken, + PIdToken: t1.PIdToken, + StandardClaims: jwtmanager.StandardClaims, } json.Unmarshal([]byte(claimjson), &customClaims.Claims) } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index f044e5bf..0373f6be 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -312,12 +312,6 @@ func fixConfigOptions() { Cfg.Headers.Redirect = "X-" + Branding.CcName + "-Requested-URI" } - if len(Cfg.JWT.SigningMethod) == 0 { - Cfg.JWT.SigningMethod = "HS256" - } else { - Cfg.JWT.SigningMethod = strings.ToUpper(Cfg.JWT.SigningMethod) - } - // jwt defaults if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") && len(Cfg.JWT.Secret) == 0 { Cfg.JWT.Secret = getOrGenerateJWTSecret() From 906a690f70c11da07e17e414327315b5ea3a2389 Mon Sep 17 00:00:00 2001 From: arvon Date: Thu, 28 Jan 2021 11:21:03 +0800 Subject: [PATCH 540/736] add Alibaba/Aliyun provider support --- handlers/handlers.go | 3 ++ pkg/cfg/oauth.go | 5 ++- pkg/providers/alibaba/alibaba.go | 65 ++++++++++++++++++++++++++++++++ pkg/structs/structs.go | 28 ++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 pkg/providers/alibaba/alibaba.go diff --git a/handlers/handlers.go b/handlers/handlers.go index 608aaeec..484ec5bc 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package handlers import ( + "github.com/vouch/vouch-proxy/pkg/providers/alibaba" "golang.org/x/oauth2" "net/http" @@ -85,6 +86,8 @@ func getProvider() Provider { return nextcloud.Provider{} case cfg.Providers.OIDC: return openid.Provider{} + case cfg.Providers.Alibaba: + return alibaba.Provider{} default: // shouldn't ever reach this since cfg checks for a properly configure `oauth.provider` log.Fatal("oauth.provider appears to be misconfigured, please check your config") diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index e5d7b41d..7278d5c2 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -42,6 +42,7 @@ var ( HomeAssistant: "homeassistant", OpenStax: "openstax", Nextcloud: "nextcloud", + Alibaba: "alibaba", } ) @@ -56,6 +57,7 @@ type OAuthProviders struct { HomeAssistant string OpenStax string Nextcloud string + Alibaba string } // oauth config items endoint for access @@ -93,7 +95,8 @@ func oauthBasicTest() error { GenOAuth.Provider != Providers.Azure && GenOAuth.Provider != Providers.OIDC && GenOAuth.Provider != Providers.OpenStax && - GenOAuth.Provider != Providers.Nextcloud { + GenOAuth.Provider != Providers.Nextcloud && + GenOAuth.Provider != Providers.Alibaba { return errors.New("configuration error: Unknown oauth provider: " + GenOAuth.Provider) } // OAuthconfig Checks diff --git a/pkg/providers/alibaba/alibaba.go b/pkg/providers/alibaba/alibaba.go new file mode 100644 index 00000000..4ec5a809 --- /dev/null +++ b/pkg/providers/alibaba/alibaba.go @@ -0,0 +1,65 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package alibaba + +import ( + "encoding/json" + "golang.org/x/oauth2" + "io/ioutil" + "net/http" + + "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/vouch/vouch-proxy/pkg/providers/common" + "github.com/vouch/vouch-proxy/pkg/structs" + "go.uber.org/zap" +) + +// Provider provider specific functions +type Provider struct{} + +var log *zap.SugaredLogger + +// Configure see main.go configure() +func (Provider) Configure() { + log = cfg.Logging.Logger +} + +// GetUserInfo provider specific call to get userinfomation +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + client, _, err := common.PrepareTokensAndClient(r, ptokens, true) + if err != nil { + return err + } + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) + if err != nil { + return err + } + defer func() { + if err := userinfo.Body.Close(); err != nil { + rerr = err + } + }() + data, _ := ioutil.ReadAll(userinfo.Body) + log.Infof("Alibaba userinfo body: %s", string(data)) + if err = common.MapClaims(data, customClaims); err != nil { + log.Error(err) + return err + } + aliUser := structs.AlibabaUser{} + if err = json.Unmarshal(data, &aliUser); err != nil { + log.Error(err) + return err + } + aliUser.PrepareUserData() + user.Username = aliUser.Username + user.Email = aliUser.Email + return nil +} diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index e42c0d60..1dcbf2f3 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -10,6 +10,8 @@ OR CONDITIONS OF ANY KIND, either express or implied. package structs +import "strconv" + // CustomClaims Temporary struct storing custom claims until JWT creation. type CustomClaims struct { Claims map[string]interface{} @@ -182,6 +184,32 @@ func (u *NextcloudUser) PrepareUserData() { } } +//Alibaba Aliyun +type AlibabaUser struct { + User + Data AliData `json:"data"` + // jwt.StandardClaims +} + +// PrepareUserData implement PersonalData interface +func (u *AlibabaUser) PrepareUserData() { + u.Username = u.Data.Username + u.Name = u.Data.Nickname + u.Email = u.Data.Email + id, _ := strconv.Atoi(u.Data.ID) + u.ID = id +} + +type AliData struct { + Sub string `json:"sub"` + Username string `json:"username"` + Nickname string `json:"nickname"` + Email string `json:"email"` + ID string `json:"ou_id"` + Phone string `json:"phone_number"` + OuName string `json:"ou_name"` +} + // Team has members and provides acess to sites type Team struct { Name string `json:"name" mapstructure:"name"` From 10f100058e24e2f7b6bb8b5bb12bbaf10873b054 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 30 Jan 2021 17:16:47 -0800 Subject: [PATCH 541/736] #354 500 error for token creation fail --- pkg/responses/responses.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index f3f6d6de..1319d1c7 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -114,6 +114,18 @@ func Error403(w http.ResponseWriter, r *http.Request, e error) { renderError(w, "403 Forbidden") } +// Error500 Internal Error +// something is not right, hopefully this never happens +func Error500(w http.ResponseWriter, r *http.Request, e error) { + log.Error(e) + log.Infof("If this error persists it may be worthy of a bug report but please check your setup first. See the README at %s", cfg.Branding.URL) + addErrandCancelRequest(r) + cookie.ClearCookie(w, r) + w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) + w.WriteHeader(http.StatusInternalServerError) + renderError(w, "500 - Internal Server Error") +} + // cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler` func addErrandCancelRequest(r *http.Request) { ctx, cancel := context.WithCancel(r.Context()) From f926918ba85b2237556b1bd5bcf8b8c918bd40ff Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 30 Jan 2021 17:24:04 -0800 Subject: [PATCH 542/736] #354 clarify audience (aud) check * move claims.Sites into claims.Audience * move check Site to check Audience * general cleanup * rename CreateUserTokenString to NewVPJWT --- handlers/auth.go | 12 +++++-- handlers/handlers_test.go | 4 +-- handlers/validate.go | 2 +- handlers/validate_test.go | 16 +++++---- pkg/jwtmanager/jwtmanager.go | 55 ++++++++++++++++--------------- pkg/jwtmanager/jwtmanager_test.go | 8 ++--- 6 files changed, 54 insertions(+), 43 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index 3c2493b0..b277bdcb 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -97,7 +97,13 @@ func AuthStateHandler(w http.ResponseWriter, r *http.Request) { // SUCCESS!! they are authorized // issue the jwt - tokenstring := jwtmanager.CreateUserTokenString(user, customClaims, ptokens) + + tokenstring, err := jwtmanager.NewVPJWT(user, customClaims, ptokens) + if err != nil { + responses.Error500(w, r, fmt.Errorf("/auth Token creation failure: %w . Please seek support from your administrator", err)) + return + + } cookie.SetCookie(w, r, tokenstring) // get the originally requested URL so we can send them on their way @@ -156,10 +162,10 @@ func verifyUser(u interface{}) (bool, error) { // Domains case len(cfg.Cfg.Domains) != 0: if domains.IsUnderManagement(user.Email) { - log.Debugf("verifyUser: Success! Email %s found within a "+cfg.Branding.FullName+" managed domain", user.Email) + log.Debugf("verifyUser: Success! Email %s found within a %s managed domain", user.Email, cfg.Branding.FullName) return true, nil } - return false, fmt.Errorf("verifyUser: Email %s is not within a "+cfg.Branding.FullName+" managed domain", user.Email) + return false, fmt.Errorf("verifyUser: Email %s is not within a %s managed domain", user.Email, cfg.Branding.FullName) // nothing configured, allow everyone through default: diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 6a968940..76877167 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -142,7 +142,6 @@ func init() { lc = jwtmanager.VouchClaims{ u1.Username, - jwtmanager.Sites, customClaims.Claims, t1.PAccessToken, t1.PIdToken, @@ -164,7 +163,8 @@ func TestParsedIdPTokens(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { setUp(tt.configFile) - uts := jwtmanager.CreateUserTokenString(u1, customClaims, t1) + uts, err := jwtmanager.NewVPJWT(u1, customClaims, t1) + assert.NoError(t, err) utsParsed, _ := jwtmanager.ParseTokenString(uts) utsPtokens, _ := jwtmanager.PTokenClaims(utsParsed) diff --git a/handlers/validate.go b/handlers/validate.go index 30a3ce01..bc01bf32 100644 --- a/handlers/validate.go +++ b/handlers/validate.go @@ -51,7 +51,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } if !cfg.Cfg.AllowAllUsers { - if !claims.SiteInClaims(r.Host) { + if !claims.SiteInAudience(r.Host) { send401or200PublicAccess(w, r, fmt.Errorf("http header 'Host: %s' not authorized for configured `vouch.domains` (is Host being sent properly?)", r.Host)) return diff --git a/handlers/validate_test.go b/handlers/validate_test.go index 7d82a3f1..645271fa 100644 --- a/handlers/validate_test.go +++ b/handlers/validate_test.go @@ -32,7 +32,8 @@ func BenchmarkValidateRequestHandler(b *testing.B) { tokens := structs.PTokens{} customClaims := structs.CustomClaims{} - userTokenString := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + userTokenString, err := jwtmanager.NewVPJWT(*user, customClaims, tokens) + assert.NoError(b, err) c := &http.Cookie{ // Name: cfg.Cfg.Cookie.Name + "_1of1", @@ -70,12 +71,13 @@ func TestValidateRequestHandlerPerf(t *testing.T) { tokens := structs.PTokens{} customClaims := structs.CustomClaims{} - userTokenString := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + vpjwt, err := jwtmanager.NewVPJWT(*user, customClaims, tokens) + assert.NoError(t, err) c := &http.Cookie{ // Name: cfg.Cfg.Cookie.Name + "_1of1", Name: cfg.Cfg.Cookie.Name, - Value: userTokenString, + Value: vpjwt, Expires: time.Now().Add(1 * time.Hour), } @@ -154,7 +156,8 @@ func TestValidateRequestHandlerWithGroupClaims(t *testing.T) { tokens := structs.PTokens{} user := &structs.User{Username: "testuser", Email: "test@example.com", Name: "Test Name"} - userTokenString := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + vpjwt, err := jwtmanager.NewVPJWT(*user, customClaims, tokens) + assert.NoError(t, err) req, err := http.NewRequest("GET", "/validate", nil) if err != nil { @@ -164,7 +167,7 @@ func TestValidateRequestHandlerWithGroupClaims(t *testing.T) { req.AddCookie(&http.Cookie{ // Name: cfg.Cfg.Cookie.Name + "_1of1", Name: cfg.Cfg.Cookie.Name, - Value: userTokenString, + Value: vpjwt, Expires: time.Now().Add(1 * time.Hour), }) @@ -209,7 +212,8 @@ func TestJWTCacheHandler(t *testing.T) { tokens := structs.PTokens{} customClaims := structs.CustomClaims{} - jwt := jwtmanager.CreateUserTokenString(*user, customClaims, tokens) + jwt, err := jwtmanager.NewVPJWT(*user, customClaims, tokens) + assert.NoError(t, err) badjwt := strings.ReplaceAll(jwt, "a", "z") badjwt = strings.ReplaceAll(badjwt, "b", "x") diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index e7d7fd7b..68c4fe94 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -29,12 +29,11 @@ import ( "github.com/vouch/vouch-proxy/pkg/structs" ) -// const numSites = 2 +const comma = "," // VouchClaims jwt Claims specific to vouch type VouchClaims struct { - Username string `json:"username"` - Sites []string `json:"sites"` // tempting to make this a map but the array is fewer characters in the jwt + Username string `json:"username"` CustomClaims map[string]interface{} PAccessToken string PIdToken string @@ -44,48 +43,52 @@ type VouchClaims struct { // StandardClaims jwt.StandardClaims implementation var StandardClaims jwt.StandardClaims -// CustomClaims implementation -// var CustomClaims map[string]interface{} - -// Sites added to VouchClaims -var Sites []string var logger *zap.Logger var log *zap.SugaredLogger +var aud string // Configure see main.go configure() func Configure() { log = cfg.Logging.Logger logger = cfg.Logging.FastLogger cacheConfigure() + aud = audience() StandardClaims = jwt.StandardClaims{ - Issuer: cfg.Cfg.JWT.Issuer, + Issuer: cfg.Cfg.JWT.Issuer, + Audience: aud, } - populateSites() } -func populateSites() { - Sites = make([]string, 0) +// `aud` of the issued JWT https://tools.ietf.org/html/rfc7519#section-4.1.3 +func audience() string { + aud := make([]string, 0) // TODO: the Sites that end up in the JWT come from here // if we add fine grain ability (ACL?) to the equation // then we're going to have to add something fancier here for i := 0; i < len(cfg.Cfg.Domains); i++ { - Sites = append(Sites, cfg.Cfg.Domains[i]) + aud = append(aud, cfg.Cfg.Domains[i]) + } + if cfg.Cfg.Cookie.Domain != "" { + aud = append(aud, cfg.Cfg.Cookie.Domain) } + return strings.Join(aud, comma) } -// CreateUserTokenString converts user to signed jwt -func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, ptokens structs.PTokens) string { +// NewVPJWT issue a signed Vouch Proxy JWT for a user +func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs.PTokens) (string, error) { // User`token` // u.PrepareUserData() claims := VouchClaims{ u.Username, - Sites, customClaims.Claims, ptokens.PAccessToken, ptokens.PIdToken, StandardClaims, } + claims.Audience = aud + claims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix() + // https://github.com/vouch/vouch-proxy/issues/287 if cfg.Cfg.Headers.AccessToken == "" { claims.PAccessToken = "" @@ -95,8 +98,6 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt claims.PIdToken = "" } - claims.StandardClaims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix() - // https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims token := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), claims) @@ -107,15 +108,15 @@ func CreateUserTokenString(u structs.User, customClaims structs.CustomClaims, pt ss, err := token.SignedString([]byte(cfg.Cfg.JWT.Secret)) // ss, err := token.SignedString([]byte("testing")) if ss == "" || err != nil { - log.Errorf("signed token error: %s", err) + return "", fmt.Errorf("New JWT: signed token error: %s", err) } if cfg.Cfg.JWT.Compress { ss, err = compressAndEncodeTokenString(ss) if ss == "" || err != nil { - log.Errorf("compressed token error: %s", err) + return "", fmt.Errorf("New JWT: compressed token error: %w", err) } } - return ss + return ss, nil } // TokenIsValid gett better error reporting @@ -141,11 +142,11 @@ func TokenIsValid(token *jwt.Token, err error) bool { func SiteInToken(site string, token *jwt.Token) bool { if claims, ok := token.Claims.(*VouchClaims); ok { log.Debugf("site %s claim %v", site, claims) - if claims.SiteInClaims(site) { + if claims.SiteInAudience(site) { return true } } - log.Errorf("site %s not found in token", site) + log.Errorf("site %s not found in token audience", site) return false } @@ -168,11 +169,11 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { } -// SiteInClaims does the claim contain the value? -func (claims *VouchClaims) SiteInClaims(site string) bool { - for _, s := range claims.Sites { +// SiteInAudience does the claim contain the value? +func (claims *VouchClaims) SiteInAudience(site string) bool { + for _, s := range strings.Split(aud, comma) { if strings.Contains(site, s) { - log.Debugf("site %s is found for claims.Site %s", site, s) + log.Debugf("site %s is found for claims.Audience %s", site, s) return true } } diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index f696e0f2..9b3b7c9e 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -50,7 +50,6 @@ func init() { lc = VouchClaims{ u1.Username, - Sites, customClaims.Claims, t1.PAccessToken, t1.PIdToken, @@ -60,7 +59,7 @@ func init() { } func TestClaims(t *testing.T) { - populateSites() + aud = audience() log.Debugf("jwt config %s %d", string(cfg.Cfg.JWT.Secret), cfg.Cfg.JWT.MaxAge) assert.NotEmpty(t, cfg.Cfg.JWT.Secret) assert.NotEmpty(t, cfg.Cfg.JWT.MaxAge) @@ -70,9 +69,10 @@ func TestClaims(t *testing.T) { // log.Infof("lc d %s", d.String()) // lc.StandardClaims.ExpiresAt = now.Add(time.Duration(ExpiresAtMinutes) * time.Minute).Unix() // log.Infof("lc expiresAt %d", now.Unix()-lc.StandardClaims.ExpiresAt) - uts := CreateUserTokenString(u1, customClaims, t1) + uts, err := NewVPJWT(u1, customClaims, t1) + assert.NoError(t, err) utsParsed, _ := ParseTokenString(uts) log.Infof("utsParsed: %+v", utsParsed) - log.Infof("Sites: %+v", Sites) + log.Infof("Audience: %+v", aud) assert.True(t, SiteInToken(cfg.Cfg.Domains[0], utsParsed)) } From 33530cda47b0528dcd8ff8dadc24474879d0416b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 18 Feb 2021 13:54:40 -0800 Subject: [PATCH 543/736] replace latency min --> mean --- handlers/validate_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/validate_test.go b/handlers/validate_test.go index 645271fa..1889d6f9 100644 --- a/handlers/validate_test.go +++ b/handlers/validate_test.go @@ -117,7 +117,7 @@ func TestValidateRequestHandlerPerf(t *testing.T) { t.Logf("99th percentile latencies: %s", metrics.Latencies.P99) t.Logf("95th percentile latencies: %s", metrics.Latencies.P95) t.Logf("50th percentile latencies: %s", metrics.Latencies.P50) - t.Logf("min latencies: %s", metrics.Latencies.Min) + t.Logf("mean latencies: %s", metrics.Latencies.Mean) t.Logf("max latencies: %s", metrics.Latencies.Max) t.Logf("/validate 95th percentile latency is higher than %s", limit) if mustFail { From 2f97af49b840833a39047d8576ac301495fed3f7 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 18 Feb 2021 14:32:16 -0800 Subject: [PATCH 544/736] golang 1.15 builder image --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9da63e31..7175513e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.14 AS builder +FROM golang:1.15 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 7801b35d..169e0315 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.14 AS builder +FROM golang:1.15 AS builder LABEL maintainer="vouch@bnf.net" From d4c5a4abf197c02d9bc77093e639c130a99f6fdb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 18 Feb 2021 14:34:10 -0800 Subject: [PATCH 545/736] fix #361 build errors by using go modules system --- do.sh | 11 +- go.mod | 39 ++++ go.sum | 675 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 724 insertions(+), 1 deletion(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/do.sh b/do.sh index bb7f33df..a0dbb97a 100755 --- a/do.sh +++ b/do.sh @@ -58,11 +58,17 @@ drun () { docker stop $NAME docker rm $NAME fi + WITHCERTS="" + if [ -d "${SDIR}/certs" ] && [ -z $(find ${SDIR}/certs -type d -empty) ]; then + WITHCERTS="-v ${SDIR}/certs:/certs" + fi + CMD="docker run --rm -i -t -p ${HTTPPORT}:${HTTPPORT} --name $NAME -v ${SDIR}/config:/config + $WITHCERTS $IMAGE $* " echo $CMD @@ -90,7 +96,8 @@ watch () { goget () { # install all the things - go get -t -v ./... + go get -u -v ./... + go mod tidy } REDACT="" @@ -159,6 +166,8 @@ test() { if [ -z "$VOUCH_CONFIG" ]; then export VOUCH_CONFIG="$SDIR/config/testing/test_config.yml" fi + + go get -t ./... # test all the things if [ -n "$*" ]; then # go test -v -race $EXTRA_TEST_ARGS $* diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..d77cb85f --- /dev/null +++ b/go.mod @@ -0,0 +1,39 @@ +module github.com/vouch/vouch-proxy + +go 1.15 + +require ( + cloud.google.com/go v0.77.0 // indirect + github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/google/go-cmp v0.5.4 + github.com/gorilla/mux v1.8.0 + github.com/gorilla/sessions v1.2.1 + github.com/influxdata/tdigest v0.0.1 // indirect + github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 + github.com/kelseyhightower/envconfig v1.4.0 + github.com/magiconair/properties v1.8.4 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/mapstructure v1.4.1 + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pelletier/go-toml v1.8.1 // indirect + github.com/spf13/afero v1.5.1 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.7.1 + github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect + github.com/stretchr/testify v1.5.1 + github.com/theckman/go-securerandom v0.1.1 + github.com/tsenart/vegeta v12.7.0+incompatible + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.16.0 + golang.org/x/net v0.0.0-20210119194325-5f4716e94777 + golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 + golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..f4ef29e4 --- /dev/null +++ b/go.sum @@ -0,0 +1,675 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ= +cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= +github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= +github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= +github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= +github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g= +golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6 h1:4WsZyVtkthqrHTbDCJfiTs8IWNYE4uvsSDgaV6xpp+o= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +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= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 416cfb63bc8d982148348cf7ffe0d9afbda4ffc3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 18 Feb 2021 14:43:34 -0800 Subject: [PATCH 546/736] fix #361 with go modules, upgrade Docker to go 1.15 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 11 +- go.mod | 39 +++ go.sum | 675 ++++++++++++++++++++++++++++++++++++++ handlers/validate_test.go | 2 +- 6 files changed, 727 insertions(+), 4 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/Dockerfile b/Dockerfile index 9da63e31..7175513e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.14 AS builder +FROM golang:1.15 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 7801b35d..169e0315 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.14 AS builder +FROM golang:1.15 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/do.sh b/do.sh index bb7f33df..a0dbb97a 100755 --- a/do.sh +++ b/do.sh @@ -58,11 +58,17 @@ drun () { docker stop $NAME docker rm $NAME fi + WITHCERTS="" + if [ -d "${SDIR}/certs" ] && [ -z $(find ${SDIR}/certs -type d -empty) ]; then + WITHCERTS="-v ${SDIR}/certs:/certs" + fi + CMD="docker run --rm -i -t -p ${HTTPPORT}:${HTTPPORT} --name $NAME -v ${SDIR}/config:/config + $WITHCERTS $IMAGE $* " echo $CMD @@ -90,7 +96,8 @@ watch () { goget () { # install all the things - go get -t -v ./... + go get -u -v ./... + go mod tidy } REDACT="" @@ -159,6 +166,8 @@ test() { if [ -z "$VOUCH_CONFIG" ]; then export VOUCH_CONFIG="$SDIR/config/testing/test_config.yml" fi + + go get -t ./... # test all the things if [ -n "$*" ]; then # go test -v -race $EXTRA_TEST_ARGS $* diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..d77cb85f --- /dev/null +++ b/go.mod @@ -0,0 +1,39 @@ +module github.com/vouch/vouch-proxy + +go 1.15 + +require ( + cloud.google.com/go v0.77.0 // indirect + github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/google/go-cmp v0.5.4 + github.com/gorilla/mux v1.8.0 + github.com/gorilla/sessions v1.2.1 + github.com/influxdata/tdigest v0.0.1 // indirect + github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 + github.com/kelseyhightower/envconfig v1.4.0 + github.com/magiconair/properties v1.8.4 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/mapstructure v1.4.1 + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pelletier/go-toml v1.8.1 // indirect + github.com/spf13/afero v1.5.1 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.7.1 + github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect + github.com/stretchr/testify v1.5.1 + github.com/theckman/go-securerandom v0.1.1 + github.com/tsenart/vegeta v12.7.0+incompatible + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.16.0 + golang.org/x/net v0.0.0-20210119194325-5f4716e94777 + golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 + golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..f4ef29e4 --- /dev/null +++ b/go.sum @@ -0,0 +1,675 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ= +cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= +github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= +github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= +github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= +github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g= +golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6 h1:4WsZyVtkthqrHTbDCJfiTs8IWNYE4uvsSDgaV6xpp+o= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +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= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/handlers/validate_test.go b/handlers/validate_test.go index 645271fa..1889d6f9 100644 --- a/handlers/validate_test.go +++ b/handlers/validate_test.go @@ -117,7 +117,7 @@ func TestValidateRequestHandlerPerf(t *testing.T) { t.Logf("99th percentile latencies: %s", metrics.Latencies.P99) t.Logf("95th percentile latencies: %s", metrics.Latencies.P95) t.Logf("50th percentile latencies: %s", metrics.Latencies.P50) - t.Logf("min latencies: %s", metrics.Latencies.Min) + t.Logf("mean latencies: %s", metrics.Latencies.Mean) t.Logf("max latencies: %s", metrics.Latencies.Max) t.Logf("/validate 95th percentile latency is higher than %s", limit) if mustFail { From 7461d4b02f35558307c573344c851b340b9a172c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Feb 2021 06:14:12 -0800 Subject: [PATCH 547/736] replace version badge with shields.io tag badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89442485..60c79f48 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/vouch/vouch-proxy)](https://goreportcard.com/report/github.com/vouch/vouch-proxy) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/vouch/vouch-proxy/blob/master/LICENSE) [![Docker pulls](https://img.shields.io/docker/pulls/voucher/vouch-proxy.svg)](https://hub.docker.com/r/voucher/vouch-proxy/) -[![GitHub version](https://badge.fury.io/gh/vouch%2Fvouch-proxy.svg)](https://badge.fury.io/gh/vouch%2Fvouch-proxy) +[![GitHub version](https://img.shields.io/github/v/tag/vouch/vouch-proxy.svg?sort=semver&color=green)](https://github.com/vouch/vouch-proxy) An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. From f11168fd926cd9f7657b555aad561e625b3a7420 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Feb 2021 06:14:12 -0800 Subject: [PATCH 548/736] replace version badge with shields.io tag badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89442485..60c79f48 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/vouch/vouch-proxy)](https://goreportcard.com/report/github.com/vouch/vouch-proxy) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/vouch/vouch-proxy/blob/master/LICENSE) [![Docker pulls](https://img.shields.io/docker/pulls/voucher/vouch-proxy.svg)](https://hub.docker.com/r/voucher/vouch-proxy/) -[![GitHub version](https://badge.fury.io/gh/vouch%2Fvouch-proxy.svg)](https://badge.fury.io/gh/vouch%2Fvouch-proxy) +[![GitHub version](https://img.shields.io/github/v/tag/vouch/vouch-proxy.svg?sort=semver&color=green)](https://github.com/vouch/vouch-proxy) An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. From 3a8e365d56f8aa1e778c065df98af8ee670b430e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Feb 2021 06:29:31 -0800 Subject: [PATCH 549/736] go report card items (spelling, gofmt) --- handlers/login.go | 2 +- pkg/cfg/cfg.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 3ed34776..a7ff8f3b 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -225,7 +225,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { if cfg.GenOAuth.Provider != cfg.Providers.IndieAuth { d := domains.Matches(hostname) if d == "" { - inCookieDomain := (hostname == cfg.Cfg.Cookie.Domain || strings.HasSuffix(hostname, "." + cfg.Cfg.Cookie.Domain)) + inCookieDomain := (hostname == cfg.Cfg.Cookie.Domain || strings.HasSuffix(hostname, "."+cfg.Cfg.Cookie.Domain)) if cfg.Cfg.Cookie.Domain == "" || !inCookieDomain { return "", fmt.Errorf("%w: not within a %s managed domain", errInvalidURL, cfg.Branding.FullName) } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index fae2bf90..61f031ce 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -141,7 +141,7 @@ const ( ErrCtxKey ctxKey = 0 ) -// use a typed ctxKey to avoid context key collission +// use a typed ctxKey to avoid context key collision // https://blog.golang.org/context#TOC_3.2. type ctxKey int From 4e10aeefbf8e9eea03609af836cc6810920a78f0 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Feb 2021 13:48:51 -0800 Subject: [PATCH 550/736] #344 formatting, add README entry --- README.md | 1 + handlers/handlers.go | 4 ++-- pkg/cfg/oauth.go | 2 +- pkg/providers/alibaba/alibaba.go | 3 ++- pkg/structs/structs.go | 16 +++++++++------- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 60c79f48..5e992fd0 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Okta](https://developer.okta.com/blog/2018/08/28/nginx-auth-request) - [ADFS](https://github.com/vouch/vouch-proxy/pull/68) - [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) +- [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) - Keycloak diff --git a/handlers/handlers.go b/handlers/handlers.go index 484ec5bc..4427738f 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -11,16 +11,16 @@ OR CONDITIONS OF ANY KIND, either express or implied. package handlers import ( - "github.com/vouch/vouch-proxy/pkg/providers/alibaba" - "golang.org/x/oauth2" "net/http" "github.com/gorilla/sessions" "go.uber.org/zap" + "golang.org/x/oauth2" "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" "github.com/vouch/vouch-proxy/pkg/providers/adfs" + "github.com/vouch/vouch-proxy/pkg/providers/alibaba" "github.com/vouch/vouch-proxy/pkg/providers/azure" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/providers/github" diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 7278d5c2..210f7f80 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -42,7 +42,7 @@ var ( HomeAssistant: "homeassistant", OpenStax: "openstax", Nextcloud: "nextcloud", - Alibaba: "alibaba", + Alibaba: "alibaba", } ) diff --git a/pkg/providers/alibaba/alibaba.go b/pkg/providers/alibaba/alibaba.go index 4ec5a809..e9577246 100644 --- a/pkg/providers/alibaba/alibaba.go +++ b/pkg/providers/alibaba/alibaba.go @@ -12,10 +12,11 @@ package alibaba import ( "encoding/json" - "golang.org/x/oauth2" "io/ioutil" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 1dcbf2f3..6f4f632f 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -184,10 +184,10 @@ func (u *NextcloudUser) PrepareUserData() { } } -//Alibaba Aliyun +// AlibabaUser Aliyun type AlibabaUser struct { User - Data AliData `json:"data"` + Data AliData `json:"data"` // jwt.StandardClaims } @@ -200,14 +200,16 @@ func (u *AlibabaUser) PrepareUserData() { u.ID = id } +// AliData `data` subobject of Alibaba User response +// https://github.com/vouch/vouch-proxy/issues/344 type AliData struct { - Sub string `json:"sub"` + Sub string `json:"sub"` Username string `json:"username"` Nickname string `json:"nickname"` - Email string `json:"email"` - ID string `json:"ou_id"` - Phone string `json:"phone_number"` - OuName string `json:"ou_name"` + Email string `json:"email"` + ID string `json:"ou_id"` + Phone string `json:"phone_number"` + OuName string `json:"ou_name"` } // Team has members and provides acess to sites From 6e33d2aa9e5d5cda2595fe53c9e02e07af331db8 Mon Sep 17 00:00:00 2001 From: borduase Date: Sun, 21 Feb 2021 05:30:40 -0800 Subject: [PATCH 551/736] do.sh: Changes the shebang to: /usr/bin/env bash since in FreeBSD bash is found at /usr/local/bin/bash. See this post on stackoverflow for more details. https://stackoverflow.com/questions/16365130/what-is-the-difference-between-usr-bin-env-bash-and-usr-bin-bash do.sh Added the function Hostname() to hide the detail of querying for a host's fully-qualified domain name since how this is done can vary based on the OS. --- do.sh | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/do.sh b/do.sh index a0dbb97a..c98b017d 100755 --- a/do.sh +++ b/do.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # change dir to where this script is running @@ -18,6 +18,31 @@ NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 +#--YetAnotherBugHunter 02/20/21 +#-- Added function Hostname() to hide +#-- the detail of querying for a host's +#-- fully-qualified domain name since how +#-- this is done can vary based on the OS. + + Hostname() { + local FQDN + local HOSTNAME_CMD + + case $(uname) in + FreeBSD) HOSTNAME_CMD="hostname";; + *) HOSTNAME_CMD="hostname --fqdn" + esac + + FQDN=$($HOSTNAME_CMD) + #-- Can't test against $? since the assignment to FQDN always succeeds even if $HOSTNAME_CMD fails. + if [ "$FQDN" = "" ]; then + >&2 echo "error: Could determine the fully qualified domain name using command $HOSTNAME_CMD" + return 1 + fi + echo $FQDN + return 0; +} + run () { go run main.go } @@ -25,7 +50,7 @@ run () { build () { local VERSION=$(git describe --always --long) local DT=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # ISO-8601 - local FQDN=$(hostname --fqdn) + local FQDN=$(Hostname) local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) local BRANCH=$(git rev-parse --abbrev-ref HEAD) go build -i -v -ldflags=" -X main.version=${VERSION} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . From 09a72cab24380c955179ca46d35392dcb25203d8 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sun, 21 Feb 2021 12:37:08 -0800 Subject: [PATCH 552/736] fix #368 build on FreeBSD and Linux --- README.md | 1 + do.sh | 37 +++++++++++++++---------------------- main.go | 2 ++ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 5e992fd0..e68fa364 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,7 @@ All Vouch Proxy configuration items are documented in [config/config.yml_example - [set `HTTP_PROXY` to relay Vouch Proxy IdP requests through an outbound proxy server](https://github.com/vouch/vouch-proxy/issues/291) - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) +- [FreeBSD support](https://github.com/vouch/vouch-proxy/issues/368) Please do help us to expand this list. diff --git a/do.sh b/do.sh index c98b017d..5de70df8 100755 --- a/do.sh +++ b/do.sh @@ -18,13 +18,21 @@ NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 -#--YetAnotherBugHunter 02/20/21 -#-- Added function Hostname() to hide -#-- the detail of querying for a host's -#-- fully-qualified domain name since how -#-- this is done can vary based on the OS. +run () { + go run main.go +} - Hostname() { +build () { + local VERSION=$(git describe --always --long) + local DT=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # ISO-8601 + local FQDN=$(_hostname) + local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) + local BRANCH=$(git rev-parse --abbrev-ref HEAD) + local UNAME=$(uname) + go build -i -v -ldflags=" -X main.version=${VERSION} -X main.uname=${UNAME} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . +} + +_hostname() { local FQDN local HOSTNAME_CMD @@ -34,8 +42,7 @@ GODOC_PORT=5050 esac FQDN=$($HOSTNAME_CMD) - #-- Can't test against $? since the assignment to FQDN always succeeds even if $HOSTNAME_CMD fails. - if [ "$FQDN" = "" ]; then + if [ -z "$FQDN" ]; then >&2 echo "error: Could determine the fully qualified domain name using command $HOSTNAME_CMD" return 1 fi @@ -43,19 +50,6 @@ GODOC_PORT=5050 return 0; } -run () { - go run main.go -} - -build () { - local VERSION=$(git describe --always --long) - local DT=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # ISO-8601 - local FQDN=$(Hostname) - local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) - local BRANCH=$(git rev-parse --abbrev-ref HEAD) - go build -i -v -ldflags=" -X main.version=${VERSION} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . -} - install () { cp ./vouch-proxy ${GOPATH}/bin/vouch-proxy } @@ -346,7 +340,6 @@ profile() { go tool pprof -http=0.0.0.0:19091 http://0.0.0.0:9090/debug/pprof/profile?seconds=10 } - gofmt() { # segfault's without exec since it would just call this function infinitely :) exec gofmt -w -s . diff --git a/main.go b/main.go index d7314f82..b9ce660d 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,7 @@ var ( host = "undefined" semver = "undefined" branch = "undefined" + uname = "undefined" staticDir = "/static/" logger *zap.SugaredLogger fastlog *zap.Logger @@ -122,6 +123,7 @@ func main() { // "semver": semver, "version", version, "buildtime", builddt, + "uname", uname, "buildhost", host, "branch", branch, "semver", semver, From b928419fa0955586f035a05bed4628c61bdb2e59 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 3 Mar 2021 15:03:36 -0800 Subject: [PATCH 553/736] spelling error transposition --- handlers/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/auth.go b/handlers/auth.go index b277bdcb..0e4e491d 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -83,7 +83,7 @@ func AuthStateHandler(w http.ResponseWriter, r *http.Request) { } if err := getUserInfo(r, &user, &customClaims, &ptokens, authCodeOptions...); err != nil { - responses.Error400(w, r, fmt.Errorf("/auth Error while retreiving user info after successful login at the OAuth provider: %w", err)) + responses.Error400(w, r, fmt.Errorf("/auth Error while retrieving user info after successful login at the OAuth provider: %w", err)) return } log.Debugf("/auth/{state}/ Claims from userinfo: %+v", customClaims) From 6d8b79ac52ccc6f1eaee4151d3e227dcb984be43 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 9 Mar 2021 16:15:15 -0800 Subject: [PATCH 554/736] #320 un-rm configureOAuthClient() HT @iamareuben --- pkg/cfg/oauth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 40dc4306..b3d2b08a 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -143,6 +143,7 @@ func setProviderDefaults() { configureOAuthClient() } else if GenOAuth.Provider == Providers.Azure { setDefaultsAzure() + configureOAuthClient() } else if GenOAuth.Provider == Providers.IndieAuth { GenOAuth.CodeChallengeMethod = "S256" configureOAuthClient() From 71b8541e1d4b7b31c44befbea5839b52efad4995 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Fri, 12 Mar 2021 11:41:12 +0000 Subject: [PATCH 555/736] use the error template for Error 401 Previously this was plain text. Passing it through the existing error templates allows administrators of vouch-proxy to customize the output in the case of a auth failure. --- handlers/auth.go | 2 +- pkg/responses/responses.go | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index b277bdcb..c73b4459 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -33,7 +33,7 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { errorIDP := r.URL.Query().Get("error") if errorIDP != "" { errorDescription := r.URL.Query().Get("error_description") - responses.Error401(w, r, fmt.Errorf("/auth Error from IdP: %s - %s", errorIDP, errorDescription)) + responses.Error401HTTP(w, r, fmt.Errorf("/auth Error from IdP: %s - %s", errorIDP, errorDescription)) return } diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 1319d1c7..1ce92db8 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -57,8 +57,9 @@ func RenderIndex(w http.ResponseWriter, msg string) { // renderError html error page // something terse for the end user -func renderError(w http.ResponseWriter, msg string) { +func renderError(w http.ResponseWriter, msg string, status int) { log.Debugf("rendering error for user: %s", msg) + w.WriteHeader(status) if err := indexTemplate.Execute(w, &Index{Msg: msg}); err != nil { log.Error(err) } @@ -89,7 +90,7 @@ func Error400(w http.ResponseWriter, r *http.Request, e error) { w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusBadRequest) addErrandCancelRequest(r) - renderError(w, "400 Bad Request") + renderError(w, "400 Bad Request", http.StatusOK) } // Error401 Unauthorized the standard error @@ -103,6 +104,14 @@ func Error401(w http.ResponseWriter, r *http.Request, e error) { // renderError(w, "401 Unauthorized") } +func Error401HTTP(w http.ResponseWriter, r *http.Request, e error) { + log.Error(e) + addErrandCancelRequest(r) + cookie.ClearCookie(w, r) + w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) + renderError(w, e.Error(), http.StatusUnauthorized) +} + // Error403 Forbidden // if there's an error during /auth or if they don't pass validation in /auth func Error403(w http.ResponseWriter, r *http.Request, e error) { @@ -111,7 +120,7 @@ func Error403(w http.ResponseWriter, r *http.Request, e error) { cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusForbidden) - renderError(w, "403 Forbidden") + renderError(w, "403 Forbidden", http.StatusOK) } // Error500 Internal Error @@ -123,7 +132,7 @@ func Error500(w http.ResponseWriter, r *http.Request, e error) { cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) w.WriteHeader(http.StatusInternalServerError) - renderError(w, "500 - Internal Server Error") + renderError(w, "500 - Internal Server Error", http.StatusOK) } // cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler` From 092413b2dcb59bb81890da02dd34aff1314b4111 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:01:42 +0100 Subject: [PATCH 556/736] Generate RSA keys during testing, move key parsing to cfg.go --- config/testing/rsa.key | 51 -------------------------- config/testing/rsa.pub | 14 ------- do.sh | 9 +++++ pkg/cfg/cfg.go | 71 +++++++++++++++++++++++++++++++++++- pkg/jwtmanager/jwtmanager.go | 70 +---------------------------------- 5 files changed, 80 insertions(+), 135 deletions(-) delete mode 100644 config/testing/rsa.key delete mode 100644 config/testing/rsa.pub diff --git a/config/testing/rsa.key b/config/testing/rsa.key deleted file mode 100644 index 9a3507ef..00000000 --- a/config/testing/rsa.key +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/config/testing/rsa.pub b/config/testing/rsa.pub deleted file mode 100644 index 904fa13a..00000000 --- a/config/testing/rsa.pub +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtLXbZPJCybcLwegsi66v -NjmXZIm42kAbp/tBoH7UwJIGjv4b0Yn8jvkQKEdONNKvDQjcjrlfMCgeeV5rXLvK -iUhCMf3KbRKcGdxWESYtUF1hd3qwubQCed0Z4xJgKegDFgUCasZMQUekwktgwMqX -bGy19i2N9AHNCjXyLLQXV4ja3tVgXev8AJF0FAaYPLB2T7PFZ3xqH6kLFEWqSN6g -oF+cHIj0sCw6yRDBJmqU4oSwxCqEH3mQNYw3UK2fV/VGrNf586OHqitdfATWdQmc -5cXYeSGCqsM4OygM8VIs27SACoR0rCQT8daK2cBHPvG4YoHkUWx4STXscIMxdp5p -nLjZZxBg9KOFPapZrMAu+v8d2wgs30W8YgODxlcKK4ZVOG1B1naFT93kStvWeeNf -rswlSIo1MqyMxJ4MP5mRzvcA5xEFBuehv1XsdhxOkwXw7vMBv2DfavHxANiOP/yj -5nr3P8pakPw8LGSJFknmJ5CodXUCp4QjeCYoPB1aOKRLj1s2m/6opiIEy4he77Ev -+CYwLX7L3vljPwHwlpgSN5IT/XxkvAH/7MZB3gVfNY72lkjat5SSlVjycaHf/a96 -EPOKhEe+0LtAZEEbOtzlmM+7PLijJt/piX8/QZlSIh0hhhYCzKvOFfCNmpeDNwbI -aDFz3A4JrGgKmawgtzRdT3sCAwEAAQ== ------END PUBLIC KEY----- diff --git a/do.sh b/do.sh index 5de70df8..af65fb50 100755 --- a/do.sh +++ b/do.sh @@ -186,6 +186,15 @@ test() { export VOUCH_CONFIG="$SDIR/config/testing/test_config.yml" fi + TEST_PRIVATE_KEY_FILE="$SDIR/config/testing/rsa.key" + TEST_PUBLIC_KEY_FILE="$SDIR/config/testing/rsa.pub" + if [[ ! -f "$TEST_PRIVATE_KEY_FILE" ]]; then + openssl genrsa -out "$TEST_PRIVATE_KEY_FILE" 4096 + fi + if [[ ! -f "$TEST_PUBLIC_KEY_FILE" ]]; then + openssl rsa -in "$TEST_PRIVATE_KEY_FILE" -pubout > "$TEST_PUBLIC_KEY_FILE" + fi + go get -t ./... # test all the things if [ -n "$*" ]; then diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 7f6b503f..a0cd1c61 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -14,6 +14,7 @@ import ( "errors" "flag" "fmt" + "io/ioutil" "net/http" "os" "path" @@ -21,6 +22,7 @@ import ( "reflect" "strings" + "github.com/dgrijalva/jwt-go" "github.com/kelseyhightower/envconfig" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" @@ -123,7 +125,6 @@ var ( IsHealthCheck = false errConfigNotFound = errors.New("configuration file not found") - errConfigIsBad = errors.New("configuration file not found") ) type cmdLineFlags struct { @@ -152,7 +153,7 @@ type ctxKey int // the order of config follows the Viper conventions... // // The priority of the sources is the following: -// 1. comand line flags +// 1. command line flags // 2. env. variables // 3. config file // 4. defaults @@ -568,3 +569,69 @@ func InitForTestPurposesWithProvider(provider string) { cleanClaimsHeaders() } + +func DecryptionKey() (interface{}, error) { + if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") { + return []byte(Cfg.JWT.Secret), nil + } + + f, err := os.Open(Cfg.JWT.PublicKeyFile) + if err != nil { + return nil, fmt.Errorf("error opening Key %s: %s", Cfg.JWT.PublicKeyFile, err) + } + + keyBytes, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("error reading Key: %s", err) + } + + var key interface{} + switch { + case strings.HasPrefix(Cfg.JWT.SigningMethod, "RS"): + key, err = jwt.ParseRSAPublicKeyFromPEM(keyBytes) + case strings.HasPrefix(Cfg.JWT.SigningMethod, "ES"): + key, err = jwt.ParseECPublicKeyFromPEM(keyBytes) + default: + // signingMethod should already have been validated, this should not happen + return nil, fmt.Errorf("unexpected signing method %s", Cfg.JWT.SigningMethod) + } + + if err != nil { + return nil, fmt.Errorf("error parsing Key: %s", err) + } + + return key, nil +} + +func SigningKey() (interface{}, error) { + if strings.HasPrefix(Cfg.JWT.SigningMethod, "HS") { + return []byte(Cfg.JWT.Secret), nil + } + + f, err := os.Open(Cfg.JWT.PrivateKeyFile) + if err != nil { + return nil, fmt.Errorf("error opening RSA Key %s: %s", Cfg.JWT.PrivateKeyFile, err) + } + + keyBytes, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("error reading Key: %s", err) + } + + var key interface{} + switch { + case strings.HasPrefix(Cfg.JWT.SigningMethod, "RS"): + key, err = jwt.ParseRSAPrivateKeyFromPEM(keyBytes) + case strings.HasPrefix(Cfg.JWT.SigningMethod, "ES"): + key, err = jwt.ParseECPrivateKeyFromPEM(keyBytes) + default: + // We should have validated this before + return nil, fmt.Errorf("unexpected signing method %s", Cfg.JWT.SigningMethod) + } + + if err != nil { + return nil, fmt.Errorf("error parsing Key: %s", err) + } + + return key, nil +} diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index b6427eda..86fa0994 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -18,7 +18,6 @@ import ( "fmt" "io/ioutil" "net/http" - "os" "strings" "time" @@ -75,71 +74,6 @@ func audience() string { return strings.Join(aud, comma) } -func decryptionKey() (interface{}, error) { - if strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "HS") { - return []byte(cfg.Cfg.JWT.Secret), nil - } - - f, err := os.Open(cfg.Cfg.JWT.PublicKeyFile) - if err != nil { - return nil, fmt.Errorf("error opening Key %s: %s", cfg.Cfg.JWT.PublicKeyFile, err) - } - - keyBytes, err := ioutil.ReadAll(f) - if err != nil { - return nil, fmt.Errorf("error reading Key: %s", err) - } - - var key interface{} - switch { - case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "RS"): - key, err = jwt.ParseRSAPublicKeyFromPEM(keyBytes) - case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "ES"): - key, err = jwt.ParseECPublicKeyFromPEM(keyBytes) - default: - // signingMethod should already have been validated, this should not happen - return nil, fmt.Errorf("unexpected signing method %s", cfg.Cfg.JWT.SigningMethod) - } - - if err != nil { - return nil, fmt.Errorf("error parsing Key: %s", err) - } - - return key, nil -} - -func signingKey() (interface{}, error) { - if strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "HS") { - return []byte(cfg.Cfg.JWT.Secret), nil - } - - f, err := os.Open(cfg.Cfg.JWT.PrivateKeyFile) - if err != nil { - return nil, fmt.Errorf("error opening RSA Key %s: %s", cfg.Cfg.JWT.PrivateKeyFile, err) - } - - keyBytes, err := ioutil.ReadAll(f) - if err != nil { - return nil, fmt.Errorf("error reading Key: %s", err) - } - - var key interface{} - switch { - case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "RS"): - key, err = jwt.ParseRSAPrivateKeyFromPEM(keyBytes) - case strings.HasPrefix(cfg.Cfg.JWT.SigningMethod, "ES"): - key, err = jwt.ParseECPrivateKeyFromPEM(keyBytes) - default: - // We should have validated this before - return nil, fmt.Errorf("unexpected signing method %s", cfg.Cfg.JWT.SigningMethod) - } - - if err != nil { - return nil, fmt.Errorf("error parsing Key: %s", err) - } - - return key, nil -} // NewVPJWT issue a signed Vouch Proxy JWT for a user func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs.PTokens) (string, error) { @@ -170,7 +104,7 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs // log.Debugf("token: %v", token) log.Debugf("token created, expires: %d diff from now: %d", claims.StandardClaims.ExpiresAt, claims.StandardClaims.ExpiresAt-time.Now().Unix()) - key, err := signingKey() + key, err := cfg.SigningKey() if err != nil { log.Errorf("%s", err) } @@ -208,7 +142,7 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { log.Debugf("decompressed tokenString length %d", len(tokenString)) } - key, err := decryptionKey() + key, err := cfg.DecryptionKey() if err != nil { log.Errorf("%s", err) } From 1b8584d95571812efbbc01d11b7039809d29cbd2 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:15:00 +0100 Subject: [PATCH 557/736] Remove gitguardian cfg file --- .gitguardian.yml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitguardian.yml diff --git a/.gitguardian.yml b/.gitguardian.yml deleted file mode 100644 index c25f47f4..00000000 --- a/.gitguardian.yml +++ /dev/null @@ -1,2 +0,0 @@ -paths-ignore: - - 'config/testing/rsa*' \ No newline at end of file From 431c3745fc3c25270f957b32ee839a707dd6178f Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:22:52 +0100 Subject: [PATCH 558/736] Install openssl dep in Travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a638b8fe..6a94156e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ env: - ISTRAVIS=true before_install: + - apt-get install openssl - ./do.sh goget # - go get github.com/golang/lint/golint # Linter # - go get github.com/fzipp/gocyclo From 5c616c8f3812a6f97dab55813155a0e9660328ca Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:24:55 +0100 Subject: [PATCH 559/736] Install openssl dep in Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a94156e..f6a66a6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ env: - ISTRAVIS=true before_install: - - apt-get install openssl + - sudo apt-get install openssl - ./do.sh goget # - go get github.com/golang/lint/golint # Linter # - go get github.com/fzipp/gocyclo From 9742d28f23b161444b448e0e3e6cfd8dd00431af Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:36:36 +0100 Subject: [PATCH 560/736] Update go to 1.16 to fix go get failure --- .travis.yml | 2 +- go.mod | 16 +++++----- go.sum | 89 ++++++++++++++++++++++++++++++----------------------- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6a66a6e..1ad3a302 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.14" + - "1.16" env: - ISTRAVIS=true diff --git a/go.mod b/go.mod index d77cb85f..fe1561ad 100644 --- a/go.mod +++ b/go.mod @@ -3,37 +3,37 @@ module github.com/vouch/vouch-proxy go 1.15 require ( - cloud.google.com/go v0.77.0 // indirect + cloud.google.com/go v0.80.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/google/go-cmp v0.5.4 + github.com/google/go-cmp v0.5.5 github.com/gorilla/mux v1.8.0 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 - github.com/magiconair/properties v1.8.4 // indirect + github.com/magiconair/properties v1.8.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.4.1 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pelletier/go-toml v1.8.1 // indirect - github.com/spf13/afero v1.5.1 // indirect + github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.7.1 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/stretchr/testify v1.5.1 + github.com/stretchr/testify v1.6.1 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.16.0 - golang.org/x/net v0.0.0-20210119194325-5f4716e94777 - golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 - golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect + golang.org/x/net v0.0.0-20210326220855-61e056675ecf + golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 + golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index f4ef29e4..5d6e22f5 100644 --- a/go.sum +++ b/go.sum @@ -12,12 +12,13 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ= -cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.80.0 h1:kAdyAMrj9CjqOSGiluseVjIgAyQ3uxADYtUYR6MwYeY= +cloud.google.com/go v0.80.0/go.mod h1:fqpb6QRi1CFGAMXDoE72G+b+Ybv7dMB/T1tbExDHktI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -81,7 +82,6 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -107,6 +107,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -119,10 +120,11 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -131,11 +133,12 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -149,6 +152,7 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -213,10 +217,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -241,7 +244,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -273,19 +275,15 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= -github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -297,10 +295,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= @@ -320,17 +318,15 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= @@ -366,7 +362,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -377,7 +372,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= @@ -414,9 +408,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210326220855-61e056675ecf h1:WUcCxqQqDT0aXO4VnQbfMvp4zh7m1Gb2clVuHUAGGRE= +golang.org/x/net v0.0.0-20210326220855-61e056675ecf/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -425,9 +423,11 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -438,6 +438,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -471,20 +472,23 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g= -golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= @@ -537,7 +541,6 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -574,12 +577,13 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.42.0/go.mod h1:+Oj4s6ch2SEGtPjGqfUfZonBH0GjQH89gTeKKAEGZKI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -617,7 +621,11 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a/go.mod h1:f2Bd7+2PlaVKmvKQ52aspJZXIDaRQBVdOOBfJ5i8OEs= 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= @@ -634,6 +642,7 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -643,14 +652,15 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -658,10 +668,11 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From f4501434656200067ace1e443fcc0aadd9070d1c Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 27 Mar 2021 12:55:28 +0100 Subject: [PATCH 561/736] Update go to 1.16 to fix go get failure --- .github/workflows/coverage.yml | 2 +- Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 2 +- go.mod | 2 +- go.sum | 1 - 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 29502615..3660ae08 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - go: ['1.14', '1.15'] + go: ['1.16'] # go: ['1.15'] steps: diff --git a/Dockerfile b/Dockerfile index 7175513e..e09dddc1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.15 AS builder +FROM golang:1.16 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 169e0315..0cffd220 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.15 AS builder +FROM golang:1.16 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/do.sh b/do.sh index af65fb50..e3fb13b2 100755 --- a/do.sh +++ b/do.sh @@ -13,7 +13,7 @@ fi IMAGE=voucher/vouch-proxy:latest ALPINE=voucher/vouch-proxy:alpine -GOIMAGE=golang:1.14 +GOIMAGE=golang:1.16 NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 diff --git a/go.mod b/go.mod index fe1561ad..e5318178 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vouch/vouch-proxy -go 1.15 +go 1.16 require ( cloud.google.com/go v0.80.0 // indirect diff --git a/go.sum b/go.sum index 5d6e22f5..0c6bfc2c 100644 --- a/go.sum +++ b/go.sum @@ -556,7 +556,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6 h1:4WsZyVtkthqrHTbDCJfiTs8IWNYE4uvsSDgaV6xpp+o= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= From 18b544052a21606d64723259620bdf9bcbee8856 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 7 Apr 2021 13:54:51 -0700 Subject: [PATCH 562/736] errConfigIsBad improvement and TODO --- pkg/cfg/cfg.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 61f031ce..691634b7 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -120,7 +120,8 @@ var ( IsHealthCheck = false errConfigNotFound = errors.New("configuration file not found") - errConfigIsBad = errors.New("configuration file not found") + // TODO: audit errors and use errConfigIsBad + // errConfigIsBad = errors.New("configuration file is malformed") ) type cmdLineFlags struct { From b9007f09082678180ce1d98a252cebd301531e97 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 18 May 2021 15:38:22 -0700 Subject: [PATCH 563/736] don't log the oauth client creds, even in debug --- pkg/cfg/cfg.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 691634b7..5ae5b5f5 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -202,6 +202,7 @@ func configureFromEnv() bool { log.Fatal(err.Error()) } preEnvGenOAuth := *GenOAuth + err = envconfig.Process("OAUTH", GenOAuth) if err != nil { log.Fatal(err.Error()) @@ -214,16 +215,7 @@ func configureFromEnv() bool { if preEnvConfig.LogLevel != Cfg.LogLevel { Logging.setLogLevelString(Cfg.LogLevel) } - log.Debugf("preEnvConfig %+v", preEnvConfig) - // Mask sensitive configuration items before logging - maskedCfg := *Cfg - if len(Cfg.Session.Key) != 0 { - maskedCfg.Session.Key = "XXXXXXXX" - } - if len(Cfg.JWT.Secret) != 0 { - maskedCfg.JWT.Secret = "XXXXXXXX" - } - log.Debugf("Cfg %+v", maskedCfg) + // log.Debugf("preEnvConfig %+v", preEnvConfig) log.Infof("%s configuration set from Environmental Variables", Branding.FullName) return true } @@ -295,8 +287,22 @@ func parseConfigFile() error { // consolidate config related Log.Debugf() calls so that they can be placed *after* we set the logLevel func logConfigIfDebug() { log.Debugf("cfg.RootDir: %s", RootDir) - log.Debugf("viper settings %+v", viper.AllSettings()) - log.Debugf("cfg.GenOauth %+v", GenOAuth) + // log.Debugf("viper settings %+v", viper.AllSettings()) + + // Mask sensitive configuration items before logging + maskedCfg := *Cfg + if len(Cfg.Session.Key) != 0 { + maskedCfg.Session.Key = "XXXXXXXX" + } + if len(Cfg.JWT.Secret) != 0 { + maskedCfg.JWT.Secret = "XXXXXXXX" + } + log.Debugf("Cfg %+v", maskedCfg) + + maskedGenOAuth := *GenOAuth + maskedGenOAuth.ClientID = "12345678" + maskedGenOAuth.ClientSecret = "XXXXXXXX" + log.Debugf("cfg.GenOauth %+v", maskedGenOAuth) } func fixConfigOptions() { From 61b6d62154b48ee19ec93b023740e0bc49aaaac0 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 18 May 2021 15:47:41 -0700 Subject: [PATCH 564/736] bump to go version 1.15 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a638b8fe..bea66e5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.14" + - "1.15" env: - ISTRAVIS=true From 6577317c2d00cf2b5de71e3fed1bd533313d389c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 18 May 2021 15:55:20 -0700 Subject: [PATCH 565/736] bump to go version 1.16 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bea66e5c..6ea3816a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.15" + - "1.16" env: - ISTRAVIS=true From 6970b9266154830755178157328274eeb9510b84 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 18 May 2021 16:44:24 -0700 Subject: [PATCH 566/736] bump to go version 1.16 --- .github/workflows/coverage.yml | 4 ++-- Dockerfile | 2 +- Dockerfile.alpine | 2 +- go.mod | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 29502615..d06d264d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -17,8 +17,8 @@ jobs: strategy: fail-fast: false matrix: - go: ['1.14', '1.15'] - # go: ['1.15'] + # go: ['1.14', '1.15'] + go: ['1.16'] steps: - uses: actions/setup-go@v2 diff --git a/Dockerfile b/Dockerfile index 7175513e..e09dddc1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.15 AS builder +FROM golang:1.16 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 169e0315..0cffd220 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # voucher/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.15 AS builder +FROM golang:1.16 AS builder LABEL maintainer="vouch@bnf.net" diff --git a/go.mod b/go.mod index d77cb85f..1c7795f0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vouch/vouch-proxy -go 1.15 +go 1.16 require ( cloud.google.com/go v0.77.0 // indirect From 19aaed15a7dcf0977331f0f934472a08e05f3331 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 18 May 2021 18:27:59 -0700 Subject: [PATCH 567/736] ignore rsa keys created for testing --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 465ee477..48cf5cb6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ coverage.out coverage.html.env_google .env* .cover +config/testing/rsa.key +config/testing/rsa.pub From dd116e40bc2354591a29d9586bfc447161a669de Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 20 May 2021 11:15:31 -0700 Subject: [PATCH 568/736] #375 use correct error codes, general cleanup --- pkg/responses/responses.go | 43 ++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 1ce92db8..56f4bcf7 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -59,6 +59,8 @@ func RenderIndex(w http.ResponseWriter, msg string) { // something terse for the end user func renderError(w http.ResponseWriter, msg string, status int) { log.Debugf("rendering error for user: %s", msg) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(status) if err := indexTemplate.Execute(w, &Index{Msg: msg}); err != nil { log.Error(err) @@ -85,54 +87,45 @@ func Redirect302(w http.ResponseWriter, r *http.Request, rURL string) { // Error400 Bad Request func Error400(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) - cookie.ClearCookie(w, r) - w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) - w.WriteHeader(http.StatusBadRequest) - addErrandCancelRequest(r) - renderError(w, "400 Bad Request", http.StatusOK) + cancelClearSetError(w, r, e) + renderError(w, "400 Bad Request", http.StatusBadRequest) } -// Error401 Unauthorized the standard error +// Error401 Unauthorized, the standard error returned when failing /validate // this is captured by nginx, which converts the 401 into 302 to the login page func Error401(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) - addErrandCancelRequest(r) - cookie.ClearCookie(w, r) - w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) + cancelClearSetError(w, r, e) http.Error(w, e.Error(), http.StatusUnauthorized) // renderError(w, "401 Unauthorized") } +// Error401HTTP func Error401HTTP(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) - addErrandCancelRequest(r) - cookie.ClearCookie(w, r) - w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) + cancelClearSetError(w, r, e) renderError(w, e.Error(), http.StatusUnauthorized) } // Error403 Forbidden // if there's an error during /auth or if they don't pass validation in /auth func Error403(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) - addErrandCancelRequest(r) - cookie.ClearCookie(w, r) - w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) - w.WriteHeader(http.StatusForbidden) - renderError(w, "403 Forbidden", http.StatusOK) + cancelClearSetError(w, r, e) + renderError(w, "403 Forbidden", http.StatusForbidden) } // Error500 Internal Error // something is not right, hopefully this never happens func Error500(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) + cancelClearSetError(w, r, e) log.Infof("If this error persists it may be worthy of a bug report but please check your setup first. See the README at %s", cfg.Branding.URL) - addErrandCancelRequest(r) + renderError(w, "500 - Internal Server Error", http.StatusInternalServerError) +} + +// cancelClearSetError convenience method to keep it DRY +func cancelClearSetError(w http.ResponseWriter, r *http.Request, e error) { + log.Error(e) cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) - w.WriteHeader(http.StatusInternalServerError) - renderError(w, "500 - Internal Server Error", http.StatusOK) + addErrandCancelRequest(r) } // cfg.ErrCtx is tested by `jwtmanager.JWTCacheHandler` From db40d4f913d08b198e2f1924d7de05fbf648e740 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 20 May 2021 13:06:14 -0700 Subject: [PATCH 569/736] make sure JWT expires from cache by jwt.expiration --- pkg/jwtmanager/jwtcache.go | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/pkg/jwtmanager/jwtcache.go b/pkg/jwtmanager/jwtcache.go index 5a04b49b..ffb22137 100644 --- a/pkg/jwtmanager/jwtcache.go +++ b/pkg/jwtmanager/jwtcache.go @@ -23,15 +23,15 @@ import ( // Cache in memory temporary store for responses from /validate for jwt var Cache *cache.Cache +var expire int = 20 // default 20 minutes +var dExp time.Duration func cacheConfigure() { - var expire int = 20 // default 20 minutes - if cfg.Cfg.JWT.MaxAge < expire { expire = cfg.Cfg.JWT.MaxAge } - dExp := time.Duration(expire) * time.Minute + dExp = time.Duration(expire) * time.Minute purgeCheck := dExp / 5 // log.Debugf("cacheConfigure expire %d dExp %d purgecheck %d", expire, dExp, purgeCheck) Cache = cache.New(dExp, purgeCheck) @@ -46,16 +46,13 @@ func cacheConfigure() { // JWTCacheHandler looks for a JWT and... // returns a cached response -// or passes the JWT in the context -// tests for JWTCacheHandler are present in `handlers/validate_test.go` to avoid circular imports +// or passes the request to /validate +// all tests for JWTCacheHandler are present in `handlers/validate_test.go` to avoid circular imports func JWTCacheHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // return http.HandlerFunc(func(w CaptureWriter, r *http.Request) { - - // wrap ResponseWriter - // v := CachedResponse{CaptureWriter: &CaptureWriter{ResponseWriter: w}} jwt := FindJWT(r) + // check to see if we have headers cached for this jwt if jwt != "" { if resp, found := Cache.Get(jwt); found { @@ -82,7 +79,28 @@ func JWTCacheHandler(next http.Handler) http.Handler { // r.Context().Done() is still open // cache the response headers for this jwt // log.Debug("setting cache for %+v", w.Header().Clone()) - Cache.SetDefault(jwt, w.Header().Clone()) + + claims, err := ClaimsFromJWT(jwt) + now := time.Now().Unix() + if err != nil { + log.Error("very unusual error, we found a jwt for /validate but we couldn't parse it for claims while setting it into cache, returning") + return + // log.Debugf("*HERE* claims expire, time.now.unix, dExp %d - %d = %d > %d", claims.ExpiresAt, now, claims.ExpiresAt-now, int64(dExp)) + // log.Debugf("*HERE* time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds()) %d", time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds())) + } + + // first see if the jwt's expiration will arrive before the cache expiration + // if this jwt expires in 10 minutes then we don't want to cache it for 20 + // this might happen if the jwt expiration is set to 240 minutes, and the user last logged into the IdP 230 minutes ago + // then the user went away, cache was purged and now they return with 10 minutes left before token expiration + if !claims.VerifyExpiresAt(now+int64(dExp/time.Second), true) { + jwtExpiresIn := time.Duration((claims.ExpiresAt - now) * int64(time.Second)) + log.Debugf("cache default expiration (%d) is after claim expiration (%d). setting cache experation to claim expiration for this entry", dExp, jwtExpiresIn) + Cache.Set(jwt, w.Header().Clone(), jwtExpiresIn) + } else { + Cache.SetDefault(jwt, w.Header().Clone()) + } + } }) } From 1a3c67a7f1cfdd5fe3739fbcb6d6f78b3bf64002 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 1 Jun 2021 10:10:54 -0700 Subject: [PATCH 570/736] move the #vouch irc channel to libera.chat --- .github/workflows/notify-irc.yml | 3 +++ .travis.yml | 2 +- README.md | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/notify-irc.yml b/.github/workflows/notify-irc.yml index 3cbf0b0a..c98def9c 100644 --- a/.github/workflows/notify-irc.yml +++ b/.github/workflows/notify-irc.yml @@ -10,6 +10,7 @@ jobs: if: github.event_name == 'push' with: channel: "#vouch" + server: irc.libera.chat nickname: from-github message: | ${{ github.actor }} pushed ${{ github.event.ref }} ${{ github.event.compare }} @@ -19,6 +20,7 @@ jobs: if: github.event_name == 'pull_request' with: channel: "#vouch" + server: irc.libera.chat nickname: from-github message: | ${{ github.actor }} opened PR ${{ github.event.html_url }} @@ -27,6 +29,7 @@ jobs: if: github.event_name == 'create' && github.event.ref_type == 'tag' with: channel: "#vouch" + server: irc.libera.chat nickname: from-github message: | ${{ github.actor }} tagged ${{ github.repository }} ${{ github.event.ref }} diff --git a/.travis.yml b/.travis.yml index 1ad3a302..aaf8a721 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,4 +40,4 @@ script: # tags: true # notifications: - irc: "chat.freenode.net#vouch" + irc: "irc.libera.chat#vouch" diff --git a/README.md b/README.md index e68fa364..d71fa8a8 100644 --- a/README.md +++ b/README.md @@ -394,7 +394,7 @@ TLDR: - and follow the instructions at the end to redact your Nginx config - all of those go into a [gist](https://gist.github.com/) - then [open a new issue](https://github.com/vouch/vouch-proxy/issues/new) in this repository -- or visit our IRC channel [#vouch](irc://freenode.net/#vouch) on freenode +- or visit our IRC channel [#vouch](irc.libera.chat/#vouch) on libera.chat A bug report can be generated from a docker environment using the `voucher/vouch-proxy:alpine` image... From f78e1257e01a70f90aa444a8e52b30b72c6e4875 Mon Sep 17 00:00:00 2001 From: herbrant Date: Mon, 7 Jun 2021 18:21:16 +0200 Subject: [PATCH 571/736] Added support for a custom 'relying party identifier' in a ADFS configuration --- config/config.yml_example_adfs | 1 + pkg/cfg/oauth.go | 8 +++++++- pkg/providers/adfs/adfs.go | 5 +++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example_adfs b/config/config.yml_example_adfs index fe12dcba..f2d05d39 100644 --- a/config/config.yml_example_adfs +++ b/config/config.yml_example_adfs @@ -18,6 +18,7 @@ oauth: client_secret: sauceSecret auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ + # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 # (optional) scopes: - openid - email diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 93e2a364..913c6148 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -72,6 +72,7 @@ type oauthConfig struct { LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` + RelyingPartyId string `mapstructure:"relying_party_id" envconfig:"relying_party_id"` Scopes []string `mapstructure:"scopes"` UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` @@ -180,7 +181,12 @@ func setDefaultsGoogle() { func setDefaultsADFS() { log.Info("configuring ADFS OAuth") - OAuthopts = oauth2.SetAuthURLParam("resource", GenOAuth.RedirectURL) // Needed or all claims won't be included + + if GenOAuth.RelyingPartyId == "" { + GenOAuth.RelyingPartyId = GenOAuth.RedirectURL + } + + OAuthopts = oauth2.SetAuthURLParam("resource", GenOAuth.RelyingPartyId) } func setDefaultsAzure() { diff --git a/pkg/providers/adfs/adfs.go b/pkg/providers/adfs/adfs.go index 1c55253f..dc1d7d45 100644 --- a/pkg/providers/adfs/adfs.go +++ b/pkg/providers/adfs/adfs.go @@ -14,7 +14,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "golang.org/x/oauth2" "io/ioutil" "net/http" "net/url" @@ -22,6 +21,8 @@ import ( "strconv" "strings" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -54,7 +55,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s formData := url.Values{} formData.Set("code", code) formData.Set("grant_type", "authorization_code") - formData.Set("resource", cfg.GenOAuth.RedirectURL) + formData.Set("resource", cfg.GenOAuth.RelyingPartyId) formData.Set("client_id", cfg.GenOAuth.ClientID) formData.Set("redirect_uri", cfg.GenOAuth.RedirectURL) if cfg.GenOAuth.ClientSecret != "" { From cf960f98d2b6cc9a2db28c50012812a8cb2d3306 Mon Sep 17 00:00:00 2001 From: Herbrant Date: Sat, 26 Jun 2021 00:04:17 +0200 Subject: [PATCH 572/736] Updated adfs examples --- config/config.yml_example | 16 ++++++++++++++++ config/config.yml_example_adfs | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config/config.yml_example b/config/config.yml_example index 126a2f23..e64fadc5 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -198,6 +198,7 @@ vouch: # callback_urls: OAUTH_CALLBACK_URLS # scopes: OAUTH_SCOPES # code_challenge_method: OAUTH_CODE_CHALLENGE_METHOD +# relying_party_id OAUTH_RELYING_PARTY_ID # # configure ONLY ONE of the following oauth providers @@ -260,4 +261,19 @@ oauth: auth_url: https://indielogin.com/auth callback_url: http://vouch.yourdomain.com:9090/auth + # adfs + provider: adfs + client_id: + client_secret: + auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ + token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ + # vouch-proxy use RedirectURL as relying party identifier by default, if you want a custom one: + # (resolves issue https://github.com/vouch/vouch-proxy/issues/189) + # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 + scopes: + - openid + - email + - profile + callback_url: https://vouch.yourdomain.com/auth + diff --git a/config/config.yml_example_adfs b/config/config.yml_example_adfs index f2d05d39..10ed5227 100644 --- a/config/config.yml_example_adfs +++ b/config/config.yml_example_adfs @@ -18,7 +18,9 @@ oauth: client_secret: sauceSecret auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ - # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 # (optional) + # vouch-proxy use RedirectURL as relying party identifier by default, if you want a custom one: + # (resolves issue https://github.com/vouch/vouch-proxy/issues/189) + # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 scopes: - openid - email From 9830da1069141b74fc797fda6390bd4a6957e434 Mon Sep 17 00:00:00 2001 From: herbrant Date: Sat, 26 Jun 2021 00:34:32 +0200 Subject: [PATCH 573/736] Added relying_party_id env in tests for env vars --- pkg/cfg/cfg_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index b2723f9d..5b10f401 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -216,7 +216,7 @@ func Test_configureFromEnvOAuth(t *testing.T) { senv := []string{ "OAUTH_PROVIDER", "OAUTH_CLIENT_ID", "OAUTH_CLIENT_SECRET", "OAUTH_AUTH_URL", "OAUTH_TOKEN_URL", "OAUTH_END_SESSION_ENDPOINT", "OAUTH_CALLBACK_URL", "OAUTH_USER_INFO_URL", "OAUTH_USER_TEAM_URL", "OAUTH_USER_ORG_URL", - "OAUTH_PREFERREDDOMAIN", + "OAUTH_PREFERREDDOMAIN", "OAUTH_RELYING_PARTY_ID", } // array of strings saenv := []string{"OAUTH_CALLBACK_URLS", "OAUTH_SCOPES"} @@ -247,6 +247,7 @@ func Test_configureFromEnvOAuth(t *testing.T) { GenOAuth.UserTeamURL, GenOAuth.UserOrgURL, GenOAuth.PreferredDomain, + GenOAuth.RelyingPartyId, } sacfg := [][]string{ GenOAuth.RedirectURLs, From 06331fbc4f48a679c2fa520e7c70ce1da3c5f626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Tue, 6 Jul 2021 17:27:12 +0200 Subject: [PATCH 574/736] embed the static files into the vouch binary the embed package is new to Go 1.6 https://golang.org/pkg/embed/ with this change it's no longer neccesseary to distribute the static files with vouch. all urls under the /static/ path are served from the embeded static filesystem. the static filesystem has all the files with the /static/ subdirectory so no stripping is needed. also removed the copy of static files to the Docker image --- Dockerfile | 2 -- Dockerfile.alpine | 2 -- main.go | 18 ++++++------------ pkg/cfg/cfg.go | 2 +- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index e09dddc1..2b8f65a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,8 +22,6 @@ LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY templates /templates COPY .defaults.yml /.defaults.yml -# see note for /static in main.go -COPY static /static COPY --from=builder /go/bin/vouch-proxy /vouch-proxy EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 0cffd220..48660186 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -19,8 +19,6 @@ ENV VOUCH_ROOT=/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY templates /templates COPY .defaults.yml /.defaults.yml -# see note for /static in main.go -COPY static /static # do.sh requires bash RUN apk add --no-cache bash diff --git a/main.go b/main.go index b9ce660d..bd087282 100644 --- a/main.go +++ b/main.go @@ -23,13 +23,13 @@ https://github.com/vouch/vouch-proxy#submitting-a-pull-request-for-a-new-feature */ import ( + "embed" "errors" "flag" "log" "net" "net/http" "os" - "path/filepath" "strconv" "time" @@ -57,7 +57,6 @@ var ( semver = "undefined" branch = "undefined" uname = "undefined" - staticDir = "/static/" logger *zap.SugaredLogger fastlog *zap.Logger help = flag.Bool("help", false, "show usage") @@ -68,6 +67,9 @@ var ( // doProfile = flag.Bool("profile", false, "run profiler at /debug/pprof") ) +//go:embed static +var staticFs embed.FS + // fwdToZapWriter allows us to use the zap.Logger as our http.Server ErrorLog // see https://stackoverflow.com/questions/52294334/net-http-set-custom-logger type fwdToZapWriter struct { @@ -152,16 +154,8 @@ func main() { healthH := http.HandlerFunc(handlers.HealthcheckHandler) muxR.HandleFunc("/healthcheck", timelog.TimeLog(healthH)) - // setup static - sPath, err := filepath.Abs(cfg.RootDir + staticDir) - if fastlog.Core().Enabled(zap.DebugLevel) { - if err != nil { - logger.Errorf("couldn't find static assets at %s", sPath) - } - logger.Debugf("serving static files from %s", sPath) - } - // https://golangcode.com/serve-static-assets-using-the-mux-router/ - muxR.PathPrefix(staticDir).Handler(http.StripPrefix(staticDir, http.FileServer(http.Dir(sPath)))) + // setup /static/ urls to be satisfied from the embedded /static/... fs + muxR.PathPrefix("/static/").Handler(http.FileServer(http.FS(staticFs))) // // if *doProfile { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 46357dfd..a7ce5033 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -104,7 +104,7 @@ var ( // Branding that's our name Branding = branding{"vouch", "VOUCH", "Vouch", "Vouch Proxy", "https://github.com/vouch/vouch-proxy"} - // RootDir is where Vouch Proxy looks for ./config/config.yml, ./data, ./static and ./templates + // RootDir is where Vouch Proxy looks for ./config/config.yml, ./data and ./templates RootDir string secretFile string From a4d64cc0a6e1c6ceeb6a768b31cd8aa36db357a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Tue, 6 Jul 2021 17:57:54 +0200 Subject: [PATCH 575/736] embed the template files into the vouch binary the embed package is new to Go 1.6 https://golang.org/pkg/embed/ with this change it's no longer necessary to distribute the template files with vouch. also removed the copy of template files to the Docker image --- Dockerfile | 1 - Dockerfile.alpine | 1 - handlers/handlers_test.go | 3 ++- main.go | 5 ++++- pkg/cfg/cfg.go | 2 +- pkg/responses/responses.go | 8 ++++---- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2b8f65a2..02f7971b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN ./do.sh install FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY templates /templates COPY .defaults.yml /.defaults.yml COPY --from=builder /go/bin/vouch-proxy /vouch-proxy EXPOSE 9090 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 48660186..29d984da 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -17,7 +17,6 @@ FROM alpine:latest LABEL maintainer="vouch@bnf.net" ENV VOUCH_ROOT=/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY templates /templates COPY .defaults.yml /.defaults.yml # do.sh requires bash diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index b972c422..050cfaad 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -40,7 +40,8 @@ func setUp(configFile string) { domains.Configure() jwtmanager.Configure() cookie.Configure() - responses.Configure() + var templatesFs = os.DirFS(os.Getenv("VOUCH_ROOT")) + responses.Configure(templatesFs) } diff --git a/main.go b/main.go index bd087282..971f7ae6 100644 --- a/main.go +++ b/main.go @@ -70,6 +70,9 @@ var ( //go:embed static var staticFs embed.FS +//go:embed templates +var templatesFs embed.FS + // fwdToZapWriter allows us to use the zap.Logger as our http.Server ErrorLog // see https://stackoverflow.com/questions/52294334/net-http-set-custom-logger type fwdToZapWriter struct { @@ -110,7 +113,7 @@ func configure() { domains.Configure() jwtmanager.Configure() cookie.Configure() - responses.Configure() + responses.Configure(templatesFs) handlers.Configure() timelog.Configure() } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index a7ce5033..d826b56f 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -104,7 +104,7 @@ var ( // Branding that's our name Branding = branding{"vouch", "VOUCH", "Vouch", "Vouch Proxy", "https://github.com/vouch/vouch-proxy"} - // RootDir is where Vouch Proxy looks for ./config/config.yml, ./data and ./templates + // RootDir is where Vouch Proxy looks for ./config/config.yml and ./data RootDir string secretFile string diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 56f4bcf7..68c38d0e 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -13,8 +13,8 @@ package responses import ( "errors" "html/template" + "io/fs" "net/http" - "path/filepath" "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" @@ -39,12 +39,12 @@ var ( ) // Configure see main.go configure() -func Configure() { +func Configure(templatesFs fs.FS) { log = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger - log.Debugf("responses.Configure() attempting to parse templates with cfg.RootDir: %s", cfg.RootDir) - indexTemplate = template.Must(template.ParseFiles(filepath.Join(cfg.RootDir, "templates/index.tmpl"))) + log.Debugf("responses.Configure() attempting to parse embedded templates") + indexTemplate = template.Must(template.ParseFS(templatesFs, "templates/index.tmpl")) } From 930fb8e38ed67098e39308133cd09dab193c781c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 30 Jul 2021 12:43:11 -0700 Subject: [PATCH 576/736] #189 adfs relying_party_id minor adjustments --- config/config.yml_example | 2 +- config/config.yml_example_adfs | 2 +- pkg/providers/adfs/adfs.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index e64fadc5..a9eef07e 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -268,7 +268,7 @@ oauth: auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ # vouch-proxy use RedirectURL as relying party identifier by default, if you want a custom one: - # (resolves issue https://github.com/vouch/vouch-proxy/issues/189) + # see https://github.com/vouch/vouch-proxy/issues/189 # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 scopes: - openid diff --git a/config/config.yml_example_adfs b/config/config.yml_example_adfs index 10ed5227..785de684 100644 --- a/config/config.yml_example_adfs +++ b/config/config.yml_example_adfs @@ -19,7 +19,7 @@ oauth: auth_url: https://adfs.yourdomain.com/adfs/oauth2/authorize/ token_url: https://adfs.yourdomain.com/adfs/oauth2/token/ # vouch-proxy use RedirectURL as relying party identifier by default, if you want a custom one: - # (resolves issue https://github.com/vouch/vouch-proxy/issues/189) + # see https://github.com/vouch/vouch-proxy/issues/189 # relying_party_id: 487d8ff7-80a8-4f62-b926-c2852ab06e94 scopes: - openid diff --git a/pkg/providers/adfs/adfs.go b/pkg/providers/adfs/adfs.go index dc1d7d45..32c2cebf 100644 --- a/pkg/providers/adfs/adfs.go +++ b/pkg/providers/adfs/adfs.go @@ -21,12 +21,12 @@ import ( "strconv" "strings" + "go.uber.org/zap" "golang.org/x/oauth2" "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" - "go.uber.org/zap" ) // Provider provider specific functions From 2eca9f11986e70bd27293d183a71e979ea53b223 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 31 Jul 2021 07:20:51 -0700 Subject: [PATCH 577/736] #406 migrate Docker builds to quay.io --- README.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d71fa8a8..28adae5f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![GitHub stars](https://img.shields.io/github/stars/vouch/vouch-proxy.svg)](https://github.com/vouch/vouch-proxy) [![Go Report Card](https://goreportcard.com/badge/github.com/vouch/vouch-proxy)](https://goreportcard.com/report/github.com/vouch/vouch-proxy) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/vouch/vouch-proxy/blob/master/LICENSE) -[![Docker pulls](https://img.shields.io/docker/pulls/voucher/vouch-proxy.svg)](https://hub.docker.com/r/voucher/vouch-proxy/) +[![Docker Repository on Quay](https://quay.io/repository/vouch/vouch-proxy/status 'Docker Repository on Quay')](https://quay.io/repository/vouch/vouch-proxy) [![GitHub version](https://img.shields.io/github/v/tag/vouch/vouch-proxy.svg?sort=semver&color=green)](https://github.com/vouch/vouch-proxy) An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. @@ -245,7 +245,7 @@ docker run -d \ -p 9090:9090 \ --name vouch-proxy \ -v ${PWD}/config:/config \ - voucher/vouch-proxy + quay.io/vouch/vouch-proxy ``` or @@ -259,15 +259,23 @@ docker run -d \ -e OAUTH_CLIENT_ID=1234 \ -e OAUTH_CLIENT_SECRET=secretsecret \ -e OAUTH_CALLBACK_URL=https://vouch.yourdomain.com/auth \ - voucher/vouch-proxy + quay.io/vouch/vouch-proxy ``` -Automated container builds for each Vouch Proxy release are available from [Docker Hub](https://hub.docker.com/r/voucher/vouch-proxy/). Each release produces.. +Automated container builds for each Vouch Proxy release are available from [quay.io](https://quay.io/repository/vouch/vouch-proxy). Each release produces.. + +a minimal go binary container built from `Dockerfile` + +- `quay.io/vouch/vouch-proxy:latest` +- `quay.io/vouch/vouch-proxy:vx.y.z` such as `quay.io/vouch/vouch-proxy:v0.28.0` + +an `alpine` based container built from `Dockerfile.alpine` + +- `quay.io/vouch/vouch-proxy:alpine` +- `quay.io/vouch/vouch-proxy:alpine-vx.y.z` + +Vouch Proxy `arm` images are available on [Docker Hub](https://hub.docker.com/r/voucher/vouch-proxy/) -- `voucher/vouch-proxy:latest` -- `voucher/vouch-proxy:x.y.z` -- `voucher/vouch-proxy:alpine` -- `voucher/vouch-proxy:alpine-x.y.z` - `voucher/vouch-proxy:latest-arm` ## Kubernetes Nginx Ingress @@ -396,10 +404,10 @@ TLDR: - then [open a new issue](https://github.com/vouch/vouch-proxy/issues/new) in this repository - or visit our IRC channel [#vouch](irc.libera.chat/#vouch) on libera.chat -A bug report can be generated from a docker environment using the `voucher/vouch-proxy:alpine` image... +A bug report can be generated from a docker environment using the `quay.io/vouch/vouch-proxy:alpine` image... ```!bash -docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh voucher/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret +docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh quay.io/vouch/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret ``` ### submitting a Pull Request for a new feature From dc6261cf53de960966092c34ced5f757c1d4cf0b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 31 Jul 2021 12:11:55 -0700 Subject: [PATCH 578/736] use github.com/golang-jwt/jwt --- go.mod | 30 ++--- go.sum | 232 ++++++++++++++++++----------------- pkg/cfg/cfg.go | 2 +- pkg/jwtmanager/jwtmanager.go | 5 +- 4 files changed, 132 insertions(+), 137 deletions(-) diff --git a/go.mod b/go.mod index e5318178..4b404bda 100644 --- a/go.mod +++ b/go.mod @@ -3,37 +3,29 @@ module github.com/vouch/vouch-proxy go 1.16 require ( - cloud.google.com/go v0.80.0 // indirect + cloud.google.com/go v0.89.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect - github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/google/go-cmp v0.5.5 + github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/google/go-cmp v0.5.6 github.com/gorilla/mux v1.8.0 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 - github.com/magiconair/properties v1.8.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.4.1 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pelletier/go-toml v1.8.1 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.7.1 + github.com/spf13/cast v1.4.0 // indirect + github.com/spf13/viper v1.8.1 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.16.0 - golang.org/x/net v0.0.0-20210326220855-61e056675ecf - golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 - golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + go.uber.org/zap v1.18.1 + golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 ) diff --git a/go.sum b/go.sum index 0c6bfc2c..3fa25dec 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,12 @@ cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKP cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.80.0 h1:kAdyAMrj9CjqOSGiluseVjIgAyQ3uxADYtUYR6MwYeY= -cloud.google.com/go v0.80.0/go.mod h1:fqpb6QRi1CFGAMXDoE72G+b+Ybv7dMB/T1tbExDHktI= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.89.0 h1:ZT4GU+y59fC95Mfdn2RtxuzN2gc69dzlVevQK8Ykyqs= +cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -38,23 +42,19 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -62,41 +62,34 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -108,6 +101,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -123,8 +117,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -137,11 +133,14 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -153,6 +152,9 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -165,10 +167,7 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -194,37 +193,31 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -235,83 +228,66 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/cast v1.4.0 h1:WhlbjwB9EGCc8W5Rxdkus+wmH2ASRwwTJk6tgHKwdqQ= +github.com/spf13/cast v1.4.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -319,19 +295,18 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -363,8 +338,9 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -374,14 +350,12 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -413,8 +387,10 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210326220855-61e056675ecf h1:WUcCxqQqDT0aXO4VnQbfMvp4zh7m1Gb2clVuHUAGGRE= -golang.org/x/net v0.0.0-20210326220855-61e056675ecf/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -426,8 +402,10 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 h1:D7nTwh4J0i+5mW4Zjzn5omvlr6YBcWywE6KOcatyNxY= -golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -441,10 +419,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -478,12 +453,17 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -491,12 +471,12 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -514,8 +494,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -539,6 +518,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -547,8 +527,14 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -577,7 +563,12 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.42.0/go.mod h1:+Oj4s6ch2SEGtPjGqfUfZonBH0GjQH89gTeKKAEGZKI= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -609,6 +600,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -623,8 +615,16 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a/go.mod h1:f2Bd7+2PlaVKmvKQ52aspJZXIDaRQBVdOOBfJ5i8OEs= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 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= @@ -638,10 +638,17 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -653,32 +660,29 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 46357dfd..06d005b9 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -22,7 +22,7 @@ import ( "reflect" "strings" - "github.com/dgrijalva/jwt-go" + "github.com/golang-jwt/jwt" "github.com/kelseyhightower/envconfig" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 86fa0994..cdbd5c39 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -21,7 +21,7 @@ import ( "strings" "time" - jwt "github.com/dgrijalva/jwt-go" + jwt "github.com/golang-jwt/jwt" "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -74,7 +74,6 @@ func audience() string { return strings.Join(aud, comma) } - // NewVPJWT issue a signed Vouch Proxy JWT for a user func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs.PTokens) (string, error) { // User`token` @@ -99,7 +98,7 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs claims.PIdToken = "" } - // https://godoc.org/github.com/dgrijalva/jwt-go#NewWithClaims + // https://godoc.org/github.com/golang-jwt/jwt#NewWithClaims token := jwt.NewWithClaims(jwt.GetSigningMethod(cfg.Cfg.JWT.SigningMethod), claims) // log.Debugf("token: %v", token) log.Debugf("token created, expires: %d diff from now: %d", claims.StandardClaims.ExpiresAt, claims.StandardClaims.ExpiresAt-time.Now().Unix()) From 8ca24f1ecde44f18416ee874a8966e5273c71b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Sat, 31 Jul 2021 21:15:32 +0200 Subject: [PATCH 579/736] introduce responses.LoadTemplates, responses.Configure() is back --- main.go | 3 ++- pkg/responses/responses.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 971f7ae6..9ef17ef8 100644 --- a/main.go +++ b/main.go @@ -113,7 +113,8 @@ func configure() { domains.Configure() jwtmanager.Configure() cookie.Configure() - responses.Configure(templatesFs) + responses.Configure() + responses.LoadTemplates(templatesFs) handlers.Configure() timelog.Configure() } diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 68c38d0e..dab565b9 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -39,13 +39,14 @@ var ( ) // Configure see main.go configure() -func Configure(templatesFs fs.FS) { +func Configure() { log = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger +} +func LoadTemplates(templatesFs fs.FS) { log.Debugf("responses.Configure() attempting to parse embedded templates") indexTemplate = template.Must(template.ParseFS(templatesFs, "templates/index.tmpl")) - } // RenderIndex render the response as an HTML page, mostly used in testing From ad7d1e60710b4ce293097ef20fa8ed85be85d330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Sat, 31 Jul 2021 21:25:16 +0200 Subject: [PATCH 580/736] fix responses.Configure() test too --- handlers/handlers_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 050cfaad..be19e331 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -41,7 +41,8 @@ func setUp(configFile string) { jwtmanager.Configure() cookie.Configure() var templatesFs = os.DirFS(os.Getenv("VOUCH_ROOT")) - responses.Configure(templatesFs) + responses.Configure() + responses.LoadTemplates(templatesFs) } From 8ba0c5526ff9eefc9cb637ed2c26852217ef1f0d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 2 Aug 2021 16:16:44 -0700 Subject: [PATCH 581/736] #398 hold embeded templates in cfg.Templates --- main.go | 23 ++++++++++++----------- pkg/cfg/cfg.go | 4 ++++ pkg/responses/responses.go | 5 +---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/main.go b/main.go index 9ef17ef8..cfb96aba 100644 --- a/main.go +++ b/main.go @@ -51,16 +51,16 @@ import ( // version and semver get overwritten by build with // go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" var ( - version = "undefined" - builddt = "undefined" - host = "undefined" - semver = "undefined" - branch = "undefined" - uname = "undefined" - logger *zap.SugaredLogger - fastlog *zap.Logger - help = flag.Bool("help", false, "show usage") - scheme = map[bool]string{ + version = "undefined" + builddt = "undefined" + host = "undefined" + semver = "undefined" + branch = "undefined" + uname = "undefined" + logger *zap.SugaredLogger + fastlog *zap.Logger + help = flag.Bool("help", false, "show usage") + scheme = map[bool]string{ false: "http", true: "https", } @@ -103,6 +103,8 @@ func configure() { cfg.Configure() healthcheck.CheckAndExitIfIsHealthCheck() + cfg.Templates = templatesFs + logger = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger @@ -114,7 +116,6 @@ func configure() { jwtmanager.Configure() cookie.Configure() responses.Configure() - responses.LoadTemplates(templatesFs) handlers.Configure() timelog.Configure() } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index d826b56f..142969ee 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -14,6 +14,7 @@ import ( "errors" "flag" "fmt" + "io/fs" "io/ioutil" "net/http" "os" @@ -127,6 +128,9 @@ var ( errConfigNotFound = errors.New("configuration file not found") // TODO: audit errors and use errConfigIsBad // errConfigIsBad = errors.New("configuration file is malformed") + + // Templates are loaded from the file system with a go:embed directive in main.go + Templates fs.FS ) type cmdLineFlags struct { diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index dab565b9..48942c8d 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -13,7 +13,6 @@ package responses import ( "errors" "html/template" - "io/fs" "net/http" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -42,11 +41,9 @@ var ( func Configure() { log = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger -} -func LoadTemplates(templatesFs fs.FS) { log.Debugf("responses.Configure() attempting to parse embedded templates") - indexTemplate = template.Must(template.ParseFS(templatesFs, "templates/index.tmpl")) + indexTemplate = template.Must(template.ParseFS(cfg.Templates, "templates/index.tmpl")) } // RenderIndex render the response as an HTML page, mostly used in testing From 33847ed9b120f4f7525d9195f42368b84c7390cb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 2 Aug 2021 16:43:11 -0700 Subject: [PATCH 582/736] #398 embed .defaults.yml --- Dockerfile | 1 - Dockerfile.alpine | 1 - README.md | 2 ++ main.go | 8 ++++++-- pkg/cfg/cfg.go | 19 ++++++++++++++----- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 02f7971b..16901da9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN ./do.sh install FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY .defaults.yml /.defaults.yml COPY --from=builder /go/bin/vouch-proxy /vouch-proxy EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 29d984da..9e668b0f 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -17,7 +17,6 @@ FROM alpine:latest LABEL maintainer="vouch@bnf.net" ENV VOUCH_ROOT=/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -COPY .defaults.yml /.defaults.yml # do.sh requires bash RUN apk add --no-cache bash diff --git a/README.md b/README.md index d71fa8a8..1ca5fe2f 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,8 @@ Helm Charts are maintained by [halkeye](https://github.com/halkeye) and are avai ./vouch-proxy ``` +As of `v0.29.0` all templates, static assets and configuration defaults in `.defaults.yml` are built into the static binary using [go:embed](https://pkg.go.dev/embed) directives. + ## /login and /logout endpoint redirection As of `v0.11.0` additional checks are in place to reduce [the attack surface of url redirection](https://blog.detectify.com/2019/05/16/the-real-impact-of-an-open-redirect/). diff --git a/main.go b/main.go index cfb96aba..704e6aae 100644 --- a/main.go +++ b/main.go @@ -73,6 +73,9 @@ var staticFs embed.FS //go:embed templates var templatesFs embed.FS +//go:embed .defaults.yml +var defaultsFs embed.FS + // fwdToZapWriter allows us to use the zap.Logger as our http.Server ErrorLog // see https://stackoverflow.com/questions/52294334/net-http-set-custom-logger type fwdToZapWriter struct { @@ -100,11 +103,12 @@ func configure() { os.Exit(1) } + cfg.Templates = templatesFs + cfg.Defaults = defaultsFs + cfg.Configure() healthcheck.CheckAndExitIfIsHealthCheck() - cfg.Templates = templatesFs - logger = cfg.Logging.Logger fastlog = cfg.Logging.FastLogger diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 142969ee..7b46a28e 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -11,10 +11,11 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( + "bytes" + "embed" "errors" "flag" "fmt" - "io/fs" "io/ioutil" "net/http" "os" @@ -130,7 +131,10 @@ var ( // errConfigIsBad = errors.New("configuration file is malformed") // Templates are loaded from the file system with a go:embed directive in main.go - Templates fs.FS + Templates embed.FS + + // Defaults are loaded from the file system with a go:embed directive in main.go + Defaults embed.FS ) type cmdLineFlags struct { @@ -476,10 +480,15 @@ func basicTest() error { // setDefaults set default options for most items from `.defaults.yml` in the root dir func setDefaults() { - viper.SetConfigName(".defaults") + // viper.SetConfigName(".defaults") viper.SetConfigType("yaml") - viper.AddConfigPath(RootDir) - viper.ReadInConfig() + // viper.AddConfigPath(RootDir) + // viper.ReadInConfig() + d, err := Defaults.ReadFile(".defaults.yml") + if err != nil { + log.Fatal(err) + } + viper.ReadConfig(bytes.NewBuffer(d)) if err := viper.UnmarshalKey(Branding.LCName, &Cfg); err != nil { log.Error(err) } From 4d39cb1f36165f2ebd34df91e507860a0545a8d0 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 2 Aug 2021 17:55:06 -0700 Subject: [PATCH 583/736] adjust testing environment for go:embed --- handlers/handlers_test.go | 3 --- pkg/cfg/cfg.go | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index be19e331..8c399c61 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -40,10 +40,7 @@ func setUp(configFile string) { domains.Configure() jwtmanager.Configure() cookie.Configure() - var templatesFs = os.DirFS(os.Getenv("VOUCH_ROOT")) responses.Configure() - responses.LoadTemplates(templatesFs) - } func TestVerifyUserPositiveUserInWhiteList(t *testing.T) { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 4b116afc..6a5ad5ec 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -16,6 +16,7 @@ import ( "errors" "flag" "fmt" + "io/fs" "io/ioutil" "net/http" "os" @@ -131,7 +132,7 @@ var ( // errConfigIsBad = errors.New("configuration file is malformed") // Templates are loaded from the file system with a go:embed directive in main.go - Templates embed.FS + Templates fs.FS // Defaults are loaded from the file system with a go:embed directive in main.go Defaults embed.FS @@ -563,6 +564,7 @@ func InitForTestPurposes() { // InitForTestPurposesWithProvider just for testing func InitForTestPurposesWithProvider(provider string) { Cfg = &Config{} // clear it out since we're called multiple times from subsequent tests + Logging.setLogLevel(zapcore.InfoLevel) setRootDir() // _, b, _, _ := runtime.Caller(0) @@ -575,7 +577,20 @@ func InitForTestPurposesWithProvider(provider string) { } // Configure() // setRootDir() - setDefaults() + + // can't use setDefaults for testing which is go:embed based so we do it the old way + // setDefaults() + viper.SetConfigName(".defaults") + viper.SetConfigType("yaml") + viper.AddConfigPath(RootDir) + viper.ReadInConfig() + if err := UnmarshalKey(Branding.LCName, &Cfg); err != nil { + log.Error(err) + } + + // this also mimics the go:embed testing setup + Templates = os.DirFS(RootDir) + if err := parseConfigFile(); err != nil { log.Error(err) } From 20cb366e3beed46cc5866ad9bdc091a1623c29d3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 3 Aug 2021 14:09:36 -0700 Subject: [PATCH 584/736] set cache expiration to jwt expiration --- pkg/jwtmanager/jwtcache.go | 36 ++++++++++++++----------- pkg/jwtmanager/jwtcache_test.go | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 pkg/jwtmanager/jwtcache_test.go diff --git a/pkg/jwtmanager/jwtcache.go b/pkg/jwtmanager/jwtcache.go index ffb22137..9b07462d 100644 --- a/pkg/jwtmanager/jwtcache.go +++ b/pkg/jwtmanager/jwtcache.go @@ -81,26 +81,32 @@ func JWTCacheHandler(next http.Handler) http.Handler { // log.Debug("setting cache for %+v", w.Header().Clone()) claims, err := ClaimsFromJWT(jwt) - now := time.Now().Unix() if err != nil { log.Error("very unusual error, we found a jwt for /validate but we couldn't parse it for claims while setting it into cache, returning") return - // log.Debugf("*HERE* claims expire, time.now.unix, dExp %d - %d = %d > %d", claims.ExpiresAt, now, claims.ExpiresAt-now, int64(dExp)) - // log.Debugf("*HERE* time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds()) %d", time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds())) - } - - // first see if the jwt's expiration will arrive before the cache expiration - // if this jwt expires in 10 minutes then we don't want to cache it for 20 - // this might happen if the jwt expiration is set to 240 minutes, and the user last logged into the IdP 230 minutes ago - // then the user went away, cache was purged and now they return with 10 minutes left before token expiration - if !claims.VerifyExpiresAt(now+int64(dExp/time.Second), true) { - jwtExpiresIn := time.Duration((claims.ExpiresAt - now) * int64(time.Second)) - log.Debugf("cache default expiration (%d) is after claim expiration (%d). setting cache experation to claim expiration for this entry", dExp, jwtExpiresIn) - Cache.Set(jwt, w.Header().Clone(), jwtExpiresIn) - } else { - Cache.SetDefault(jwt, w.Header().Clone()) + // log.Debugf("claims expire, time.now.unix, dExp %d - %d = %d > %d", claims.ExpiresAt, now, claims.ExpiresAt-now, int64(dExp)) + // log.Debugf("time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds()) %d", time.Duration((claims.ExpiresAt-time.Now().Unix())*time.Second.Nanoseconds())) } + cacheExp := getCacheExpirationDuration(claims) + Cache.Set(jwt, w.Header().Clone(), cacheExp) } }) } + +// getCacheExpirationDuration - return time.Duration til the jwt should be purged from cache +// first see if the jwt's expiration will arrive before the cache expiration +// if this jwt expires in 10 minutes then we don't want to cache it for 20 +// this might happen if the jwt expiration is set to 240 minutes, and the user last logged into the IdP 230 minutes ago +// then the user went away, cache was purged and now they return with 10 minutes left before token expiration +func getCacheExpirationDuration(claims *VouchClaims) time.Duration { + + now := time.Now().Unix() + expiresAt := now + int64(dExp/time.Second) + if !claims.VerifyExpiresAt(expiresAt, true) { + jwtExpiresIn := time.Duration((claims.ExpiresAt - now) * int64(time.Second)) + log.Debugf("cache default expiration (%d) is after jwt expiration (%d). setting cache expiration to claim expiration for this entry", dExp, jwtExpiresIn) + return jwtExpiresIn + } + return dExp +} diff --git a/pkg/jwtmanager/jwtcache_test.go b/pkg/jwtmanager/jwtcache_test.go new file mode 100644 index 00000000..3f57559e --- /dev/null +++ b/pkg/jwtmanager/jwtcache_test.go @@ -0,0 +1,48 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package jwtmanager + +import ( + "fmt" + "reflect" + "testing" + "time" +) + +func Test_getCacheExpirationDuration(t *testing.T) { + // default cache expire is 20 minutes, so we test +/- 5 minutes of that + expire = 17 + now := time.Now() + + claimsA := lc + claimsA.ExpiresAt = now.Add(time.Minute * time.Duration(expire+5)).Unix() + + claimsB := lc + dBexp := time.Minute * time.Duration(expire-5) + claimsB.ExpiresAt = now.Add(dBexp).Unix() + + tests := []struct { + name string + claims *VouchClaims + want time.Duration + }{ + {fmt.Sprintf("should equal %d", expire), &claimsA, dExp}, // dExp is the default expiration duration + {fmt.Sprintf("should equal %d -5", expire), &claimsB, dBexp}, + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getCacheExpirationDuration(tt.claims); !reflect.DeepEqual(got, tt.want) { + t.Errorf("getCacheExpirationDuration() = %v, want %v", got, tt.want) + } + }) + } +} From a7b7a07be00de12d68e3964b4bdfae5ff3e2ef7e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 3 Aug 2021 14:28:31 -0700 Subject: [PATCH 585/736] systemd example, claims cookie language --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06fc8f51..3a7dd71b 100644 --- a/README.md +++ b/README.md @@ -208,16 +208,17 @@ All Vouch Proxy configuration items are documented in [config/config.yml_example - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) - [FreeBSD support](https://github.com/vouch/vouch-proxy/issues/368) +- [systemd startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) Please do help us to expand this list. ### Scopes and Claims -With Vouch Proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to `user_info_url` after successful authentication. From the provider's response the required `claims` are extracted and stored in the vouch cookie. +With Vouch Proxy you can request various `scopes` (standard and custom) to obtain more information about the user or gain access to the provider's APIs. Internally, Vouch Proxy launches a requests to `user_info_url` after successful authentication. The required `claims` are extracted from the provider's response and stored in the VP cookie. ⚠️ **Additional claims and tokens will be added to the VP cookie and can make it large** -The VP cookie may get split up into several cookies, but if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. +The VP cookie may be split into several cookies to accomdate browser cookie size limits. But if you need it, you need it. Large cookies and headers require Nginx to be configured with larger buffers. See [large_client_header_buffers](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) and [proxy_buffer_size](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size) for more information. #### Setup `scopes` and `claims` in Vouch Proxy with Nginx From d5c40652e643d3d4877d51c10cc0b012a9d088f6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 10:42:03 -0700 Subject: [PATCH 586/736] use log.Warn for common "token not found" error --- pkg/responses/responses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 48942c8d..2ff29f3e 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -120,7 +120,7 @@ func Error500(w http.ResponseWriter, r *http.Request, e error) { // cancelClearSetError convenience method to keep it DRY func cancelClearSetError(w http.ResponseWriter, r *http.Request, e error) { - log.Error(e) + log.Warn(e) cookie.ClearCookie(w, r) w.Header().Set(cfg.Cfg.Headers.Error, e.Error()) addErrandCancelRequest(r) From 7dd36bf3b746eac70e2e898e7e5ac15fe6fb3e3c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 11:59:20 -0700 Subject: [PATCH 587/736] use httprouter's more performant mux --- go.mod | 2 +- go.sum | 4 ++-- main.go | 61 +++++++++++++++++++++++++++++++++------------------------ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 4b404bda..0fdb0c36 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,9 @@ require ( github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.5.6 - github.com/gorilla/mux v1.8.0 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect + github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index 3fa25dec..4f8290c5 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= @@ -200,6 +198,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= diff --git a/main.go b/main.go index 704e6aae..bea18f3d 100644 --- a/main.go +++ b/main.go @@ -35,7 +35,7 @@ import ( // "net/http/pprof" - "github.com/gorilla/mux" + "github.com/julienschmidt/httprouter" "go.uber.org/zap" "github.com/vouch/vouch-proxy/handlers" @@ -48,7 +48,7 @@ import ( "github.com/vouch/vouch-proxy/pkg/timelog" ) -// version and semver get overwritten by build with +// `version`, `semver` and others are populated during build by.. // go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" var ( version = "undefined" @@ -142,37 +142,46 @@ func main() { "tls", tls, "oauth.provider", cfg.GenOAuth.Provider) - muxR := mux.NewRouter() + // router := mux.NewRouter() + router := httprouter.New() authH := http.HandlerFunc(handlers.ValidateRequestHandler) - muxR.HandleFunc("/validate", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) - muxR.HandleFunc("/_external-auth-{id}", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) + router.HandlerFunc(http.MethodGet, "/validate", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) + router.HandlerFunc(http.MethodGet, "/_external-auth-:id", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) loginH := http.HandlerFunc(handlers.LoginHandler) - muxR.HandleFunc("/login", timelog.TimeLog(loginH)) + router.HandlerFunc(http.MethodGet, "/login", timelog.TimeLog(loginH)) logoutH := http.HandlerFunc(handlers.LogoutHandler) - muxR.HandleFunc("/logout", timelog.TimeLog(logoutH)) - - authStateH := http.HandlerFunc(handlers.AuthStateHandler) - muxR.HandleFunc("/auth/{state}/", timelog.TimeLog(authStateH)) + router.HandlerFunc(http.MethodGet, "/logout", timelog.TimeLog(logoutH)) callH := http.HandlerFunc(handlers.CallbackHandler) - muxR.HandleFunc("/auth", timelog.TimeLog(callH)) + router.HandlerFunc(http.MethodGet, "/auth/", timelog.TimeLog(callH)) + + authStateH := http.HandlerFunc(handlers.AuthStateHandler) + router.HandlerFunc(http.MethodGet, "/auth/:state/", timelog.TimeLog(authStateH)) healthH := http.HandlerFunc(handlers.HealthcheckHandler) - muxR.HandleFunc("/healthcheck", timelog.TimeLog(healthH)) + router.HandlerFunc(http.MethodGet, "/healthcheck", timelog.TimeLog(healthH)) + + // this is the documented implemenation for static file serving but it doesn't seem to work with go:embed + // router.ServeFiles("/static/*filepath", http.FS(staticFs)) + + // so instead we publish all three routes + router.Handler(http.MethodGet, "/static/css/main.css", http.FileServer(http.FS(staticFs))) + router.Handler(http.MethodGet, "/static/img/favicon.ico", http.FileServer(http.FS(staticFs))) + router.Handler(http.MethodGet, "/static/img/multicolor_V_500x500.png", http.FileServer(http.FS(staticFs))) - // setup /static/ urls to be satisfied from the embedded /static/... fs - muxR.PathPrefix("/static/").Handler(http.FileServer(http.FS(staticFs))) + // this also works for static files + // router.NotFound = http.FileServer(http.FS(staticFs)) // // if *doProfile { - // addProfilingHandlers(muxR) + // addProfilingHandlers(router) // } srv := &http.Server{ - Handler: muxR, + Handler: router, Addr: listen, // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, @@ -202,16 +211,16 @@ func checkTCPPortAvailable(listen string) { } // if you'd like to enable profiling uncomment these -// func addProfilingHandlers(muxR *mux.Router) { +// func addProfilingHandlers(router *httprouter.Router) { // // https://stackoverflow.com/questions/47452471/pprof-profile-with-julienschmidtrouter-and-benchmarks-not-profiling-handler // logger.Debugf("profiling routes added at http://%s:%d/debug/pprof/", cfg.Cfg.Listen, cfg.Cfg.Port) -// muxR.HandleFunc("/debug/pprof/", pprof.Index) -// muxR.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) -// muxR.HandleFunc("/debug/pprof/profile", pprof.Profile) -// muxR.HandleFunc("/debug/pprof/symbol", pprof.Symbol) -// muxR.HandleFunc("/debug/pprof/trace", pprof.Trace) -// muxR.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine")) -// muxR.Handle("/debug/pprof/heap", pprof.Handler("heap")) -// muxR.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate")) -// muxR.Handle("/debug/pprof/block", pprof.Handler("block")) +// router.HandlerFunc(http.MethodGet, "/debug/pprof/", pprof.Index) +// router.HandlerFunc(http.MethodGet, "/debug/pprof/cmdline", pprof.Cmdline) +// router.HandlerFunc(http.MethodGet, "/debug/pprof/profile", pprof.Profile) +// router.HandlerFunc(http.MethodGet, "/debug/pprof/symbol", pprof.Symbol) +// router.HandlerFunc(http.MethodGet, "/debug/pprof/trace", pprof.Trace) +// router.Handler(http.MethodGet, "/debug/pprof/goroutine", pprof.Handler("goroutine")) +// router.Handler(http.MethodGet, "/debug/pprof/heap", pprof.Handler("heap")) +// router.Handler(http.MethodGet, "/debug/pprof/threadcreate", pprof.Handler("threadcreate")) +// router.Handler(http.MethodGet, "/debug/pprof/block", pprof.Handler("block")) // } From f0ac39a76efef2a8c91b78b327bf3b525fb5a338 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 13:46:37 -0700 Subject: [PATCH 588/736] #406 gh action docker build and push to quay.io --- ...ker-release.yml => docker-release-arm.yml} | 2 +- .github/workflows/docker-release-quayio.yml | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) rename .github/workflows/{docker-release.yml => docker-release-arm.yml} (98%) create mode 100644 .github/workflows/docker-release-quayio.yml diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release-arm.yml similarity index 98% rename from .github/workflows/docker-release.yml rename to .github/workflows/docker-release-arm.yml index ca6d44f3..a28f9f7f 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release-arm.yml @@ -6,7 +6,7 @@ on: - master jobs: - Publish-to-docker: + publish-to-docker-arm: runs-on: ubuntu-latest env: DOCKER_TAG: latest-arm diff --git a/.github/workflows/docker-release-quayio.yml b/.github/workflows/docker-release-quayio.yml new file mode 100644 index 00000000..83dcfa48 --- /dev/null +++ b/.github/workflows/docker-release-quayio.yml @@ -0,0 +1,53 @@ +name: Publish Docker image to Quay.io + +on: + push: + branches: + - master + tags: + - 'v*' + + +jobs: + publish-to-docker-quayio: + runs-on: ubuntu-latest + env: + DOCKER_REPO: quay.io + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker repository + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + registry: ${{ env.DOCKER_REPO }} + username: ${{ secrets.QUAYIO_ROBOT_USERNAME }} + password: ${{ secrets.QUAYIO_ROBOT_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: quay.io/vouch/vouch-proxy + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push Docker image using Dockerfile + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Build and push Docker image using Dockerfile.alpine + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + file: Dockerfile.alpine + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: alpine-${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file From dc806813b07bc2d3f516cd4018b9161d6b8a0439 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 13:46:37 -0700 Subject: [PATCH 589/736] #406 gh action docker build and push to quay.io --- ...ker-release.yml => docker-release-arm.yml} | 2 +- .github/workflows/docker-release-quayio.yml | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) rename .github/workflows/{docker-release.yml => docker-release-arm.yml} (98%) create mode 100644 .github/workflows/docker-release-quayio.yml diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release-arm.yml similarity index 98% rename from .github/workflows/docker-release.yml rename to .github/workflows/docker-release-arm.yml index ca6d44f3..a28f9f7f 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release-arm.yml @@ -6,7 +6,7 @@ on: - master jobs: - Publish-to-docker: + publish-to-docker-arm: runs-on: ubuntu-latest env: DOCKER_TAG: latest-arm diff --git a/.github/workflows/docker-release-quayio.yml b/.github/workflows/docker-release-quayio.yml new file mode 100644 index 00000000..83dcfa48 --- /dev/null +++ b/.github/workflows/docker-release-quayio.yml @@ -0,0 +1,53 @@ +name: Publish Docker image to Quay.io + +on: + push: + branches: + - master + tags: + - 'v*' + + +jobs: + publish-to-docker-quayio: + runs-on: ubuntu-latest + env: + DOCKER_REPO: quay.io + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker repository + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + registry: ${{ env.DOCKER_REPO }} + username: ${{ secrets.QUAYIO_ROBOT_USERNAME }} + password: ${{ secrets.QUAYIO_ROBOT_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: quay.io/vouch/vouch-proxy + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push Docker image using Dockerfile + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Build and push Docker image using Dockerfile.alpine + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + file: Dockerfile.alpine + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: alpine-${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file From 64b6903469b8f58109858893fc557a468e48b5c5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 14:08:39 -0700 Subject: [PATCH 590/736] #406 gh action docker alpine build push to quay.io --- .../docker-release-quayio-alpine.yml | 47 +++++++++++++++++++ .github/workflows/docker-release-quayio.yml | 8 ---- 2 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/docker-release-quayio-alpine.yml diff --git a/.github/workflows/docker-release-quayio-alpine.yml b/.github/workflows/docker-release-quayio-alpine.yml new file mode 100644 index 00000000..5ae651d8 --- /dev/null +++ b/.github/workflows/docker-release-quayio-alpine.yml @@ -0,0 +1,47 @@ +name: Publish Docker image to Quay.io + +on: + push: + branches: + - master + tags: + - 'v*' + + +jobs: + publish-to-docker-quayio: + runs-on: ubuntu-latest + env: + DOCKER_REPO: quay.io + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker repository + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + registry: ${{ env.DOCKER_REPO }} + username: ${{ secrets.QUAYIO_ROBOT_USERNAME }} + password: ${{ secrets.QUAYIO_ROBOT_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: quay.io/vouch/vouch-proxy + flavor: | + prefix=alpine-,onlatest=true + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push Docker image using Dockerfile.alpine + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + file: Dockerfile.alpine + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/docker-release-quayio.yml b/.github/workflows/docker-release-quayio.yml index 83dcfa48..d6d5df3d 100644 --- a/.github/workflows/docker-release-quayio.yml +++ b/.github/workflows/docker-release-quayio.yml @@ -43,11 +43,3 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - - name: Build and push Docker image using Dockerfile.alpine - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc - with: - file: Dockerfile.alpine - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: alpine-${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file From 8288b58a3bcf2ef8ddfd6605b0eab0d182276128 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 14:22:56 -0700 Subject: [PATCH 591/736] #406 drop onlatest, name as alpine --- .github/workflows/docker-release-quayio-alpine.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-release-quayio-alpine.yml b/.github/workflows/docker-release-quayio-alpine.yml index 5ae651d8..4df1b969 100644 --- a/.github/workflows/docker-release-quayio-alpine.yml +++ b/.github/workflows/docker-release-quayio-alpine.yml @@ -1,4 +1,4 @@ -name: Publish Docker image to Quay.io +name: Publish Docker image to Quay.io using Dockerfile.alpine on: push: @@ -31,7 +31,7 @@ jobs: with: images: quay.io/vouch/vouch-proxy flavor: | - prefix=alpine-,onlatest=true + prefix=alpine- tags: | type=ref,event=branch type=semver,pattern={{version}} From e81acdab18933df8042ab182228232e6462b7dc0 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 14:43:34 -0700 Subject: [PATCH 592/736] #406 fix naming of alpine images, update README --- .github/workflows/docker-release-quayio-alpine.yml | 4 ++-- README.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-release-quayio-alpine.yml b/.github/workflows/docker-release-quayio-alpine.yml index 4df1b969..4c2a1d1f 100644 --- a/.github/workflows/docker-release-quayio-alpine.yml +++ b/.github/workflows/docker-release-quayio-alpine.yml @@ -27,11 +27,11 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@a67f45cb0f8e65cf693a0bc5bfa1c5057c623030 with: images: quay.io/vouch/vouch-proxy flavor: | - prefix=alpine- + prefix=alpine-,onlatest=true tags: | type=ref,event=branch type=semver,pattern={{version}} diff --git a/README.md b/README.md index 3a7dd71b..e6d48f78 100644 --- a/README.md +++ b/README.md @@ -268,12 +268,12 @@ Automated container builds for each Vouch Proxy release are available from [quay a minimal go binary container built from `Dockerfile` - `quay.io/vouch/vouch-proxy:latest` -- `quay.io/vouch/vouch-proxy:vx.y.z` such as `quay.io/vouch/vouch-proxy:v0.28.0` +- `quay.io/vouch/vouch-proxy:x.y.z` such as `quay.io/vouch/vouch-proxy:0.28.0` an `alpine` based container built from `Dockerfile.alpine` -- `quay.io/vouch/vouch-proxy:alpine` -- `quay.io/vouch/vouch-proxy:alpine-vx.y.z` +- `quay.io/vouch/vouch-proxy:alpine-latest` +- `quay.io/vouch/vouch-proxy:alpine-x.y.z` Vouch Proxy `arm` images are available on [Docker Hub](https://hub.docker.com/r/voucher/vouch-proxy/) From 62eb090f7c61e164e8b097b04d210a4993f8d186 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 15:10:40 -0700 Subject: [PATCH 593/736] #406 use travis instead of quay.io badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6d48f78..44d4e0dd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Vouch Proxy [![GitHub stars](https://img.shields.io/github/stars/vouch/vouch-proxy.svg)](https://github.com/vouch/vouch-proxy) +[![Build Status](https://travis-ci.org/vouch/vouch-proxy.svg?branch=master)](https://travis-ci.org/vouch/vouch-proxy) [![Go Report Card](https://goreportcard.com/badge/github.com/vouch/vouch-proxy)](https://goreportcard.com/report/github.com/vouch/vouch-proxy) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/vouch/vouch-proxy/blob/master/LICENSE) -[![Docker Repository on Quay](https://quay.io/repository/vouch/vouch-proxy/status 'Docker Repository on Quay')](https://quay.io/repository/vouch/vouch-proxy) [![GitHub version](https://img.shields.io/github/v/tag/vouch/vouch-proxy.svg?sort=semver&color=green)](https://github.com/vouch/vouch-proxy) An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) module. Vouch Proxy can protect all of your websites at once. From c98de26a7030e1a9c1bbefd94b06a9745b97599f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 18:32:18 -0700 Subject: [PATCH 594/736] copy the struct, not the address --- pkg/cfg/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 6a5ad5ec..accfbdaf 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -306,7 +306,7 @@ func logConfigIfDebug() { // log.Debugf("viper settings %+v", viper.AllSettings()) // Mask sensitive configuration items before logging - maskedCfg := *Cfg + maskedCfg := Cfg if len(Cfg.Session.Key) != 0 { maskedCfg.Session.Key = "XXXXXXXX" } From 8efcbd2d1574d8865ffb67f6edd0e535acfbd719 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 4 Aug 2021 22:11:21 -0700 Subject: [PATCH 595/736] Revert "copy the struct, not the address" This reverts commit c98de26a7030e1a9c1bbefd94b06a9745b97599f. --- pkg/cfg/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index accfbdaf..6a5ad5ec 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -306,7 +306,7 @@ func logConfigIfDebug() { // log.Debugf("viper settings %+v", viper.AllSettings()) // Mask sensitive configuration items before logging - maskedCfg := Cfg + maskedCfg := *Cfg if len(Cfg.Session.Key) != 0 { maskedCfg.Session.Key = "XXXXXXXX" } From 8567f1240d86d50d74a1131a5c7c2085cc721a56 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 5 Aug 2021 16:29:34 -0700 Subject: [PATCH 596/736] slack oidc example and app manifest --- README.md | 1 + config/config.yml_example_slack | 32 +++++++++++++++++++ .../slack/vouch-slack-oidc-app-manifest.yml | 17 ++++++++++ 3 files changed, 50 insertions(+) create mode 100644 config/config.yml_example_slack create mode 100644 examples/slack/vouch-slack-oidc-app-manifest.yml diff --git a/README.md b/README.md index 44d4e0dd..5db2ab96 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - GitHub Enterprise - [IndieAuth](https://indieauth.spec.indieweb.org/) - [Okta](https://developer.okta.com/blog/2018/08/28/nginx-auth-request) +- [Slack](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_slack) - [ADFS](https://github.com/vouch/vouch-proxy/pull/68) - [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) - [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) diff --git a/config/config.yml_example_slack b/config/config.yml_example_slack new file mode 100644 index 00000000..8a13461b --- /dev/null +++ b/config/config.yml_example_slack @@ -0,0 +1,32 @@ + +# vouch config +# bare minimum to get vouch running with Slack + +vouch: + domains: + - yourdomain.com + + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea + # allowAllUsers: true + + # cookie: + # secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + + +oauth: + # create a new OAuth application at: + # https://api.slack.com/apps + # use the manifest at `examples/slack/vouch-slack-oidc-app-manifest.yml` + # then install the new app to your slack instance + provider: oidc + # careful! the slack client_id must be single quoted so that the yaml parser + # doesn't interpret it as a number (because yaml is actually javascript) + client_id: 'xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxx' + client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + callback_url: https://vouch.yourdomain.com/auth + # from https://slack.com/.well-known/openid-configuration + auth_url: https://slack.com/openid/connect/authorize + token_url: https://slack.com/api/openid.connect.token + user_info_url: https://slack.com/api/openid.connect.userInfo diff --git a/examples/slack/vouch-slack-oidc-app-manifest.yml b/examples/slack/vouch-slack-oidc-app-manifest.yml new file mode 100644 index 00000000..e8336b46 --- /dev/null +++ b/examples/slack/vouch-slack-oidc-app-manifest.yml @@ -0,0 +1,17 @@ +_metadata: + major_version: 1 + minor_version: 1 +display_information: + name: Vouch Proxy - Login to Slack + description: enforce login to Slack to provide authorized access to your websites + background_color: "#002da8" +oauth_config: + scopes: + user: + - email + - openid + - profile +settings: + org_deploy_enabled: false + socket_mode_enabled: false + token_rotation_enabled: false From 252d46b6d867183d3d23f859e6c776c748b78080 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 5 Aug 2021 16:30:13 -0700 Subject: [PATCH 597/736] fix #304 add CHANGELOG.md --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..ba2b6489 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog for Vouch Proxy + +## Unreleased + +Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. + +## v0.32.0 + +- [slack oidc example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_slack) and [slack app manifest](https://github.com/vouch/vouch-proxy/blob/master/examples/slack/vouch-slack-oidc-app-manifest.yml) +- [CHANGELOG.md](https://github.com/vouch/vouch-proxy/blob/master/CHANGELOG.md) + +## v0.31.0 + +- [use quay.io](https://quay.io/repository/vouch/vouch-proxy?tab=tags) instead of Docker Hub for docker image hosting +- use [httprouter's](https://github.com/julienschmidt/httprouter) more performant mux + +## v0.29.0 + +- embed static assets at templates using [go:embed](https://golang.org/pkg/embed/) + +## v0.28.0 + +- add support for a custom 'relying party identifier' for ADFS + +_the rest is history_ and can be teased out with `git log` From 51c78b3c4fafa33fd163903d2b2724d3afc69c0d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 5 Aug 2021 16:47:00 -0700 Subject: [PATCH 598/736] add note regarding redirect_urls --- CHANGELOG.md | 2 +- config/config.yml_example_slack | 1 + examples/slack/vouch-slack-oidc-app-manifest.yml | 7 +++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba2b6489..769f6da2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Coming soon! Please document any work in progress here as part of your PR. It wi ## v0.29.0 -- embed static assets at templates using [go:embed](https://golang.org/pkg/embed/) +- embed static assets as templates using [go:embed](https://golang.org/pkg/embed/) ## v0.28.0 diff --git a/config/config.yml_example_slack b/config/config.yml_example_slack index 8a13461b..b478b7cc 100644 --- a/config/config.yml_example_slack +++ b/config/config.yml_example_slack @@ -19,6 +19,7 @@ oauth: # create a new OAuth application at: # https://api.slack.com/apps # use the manifest at `examples/slack/vouch-slack-oidc-app-manifest.yml` + # but be sure to match the `callback_url`'s below to the `redirect_urls` in the manifest # then install the new app to your slack instance provider: oidc # careful! the slack client_id must be single quoted so that the yaml parser diff --git a/examples/slack/vouch-slack-oidc-app-manifest.yml b/examples/slack/vouch-slack-oidc-app-manifest.yml index e8336b46..edc3183e 100644 --- a/examples/slack/vouch-slack-oidc-app-manifest.yml +++ b/examples/slack/vouch-slack-oidc-app-manifest.yml @@ -6,12 +6,11 @@ display_information: description: enforce login to Slack to provide authorized access to your websites background_color: "#002da8" oauth_config: + # these need to match the + redirect_urls: + - https://vouch.yourdomain.com/auth scopes: user: - email - openid - profile -settings: - org_deploy_enabled: false - socket_mode_enabled: false - token_rotation_enabled: false From 438705e214c49a262f8f1b5791a74407b2d33f48 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 5 Aug 2021 17:25:15 -0700 Subject: [PATCH 599/736] add `-version` flag --- do.sh | 2 +- main.go | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/do.sh b/do.sh index 6f1060cb..8fbdbb5b 100755 --- a/do.sh +++ b/do.sh @@ -29,7 +29,7 @@ build () { local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) local BRANCH=$(git rev-parse --abbrev-ref HEAD) local UNAME=$(uname) - go build -i -v -ldflags=" -X main.version=${VERSION} -X main.uname=${UNAME} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . + go build -v -ldflags=" -X main.version=${VERSION} -X main.uname=${UNAME} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . } _hostname() { diff --git a/main.go b/main.go index bea18f3d..965e7603 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ import ( "embed" "errors" "flag" + "fmt" "log" "net" "net/http" @@ -51,16 +52,17 @@ import ( // `version`, `semver` and others are populated during build by.. // go build -i -v -ldflags="-X main.version=$(git describe --always --long) -X main.semver=v$(git semver get)" var ( - version = "undefined" - builddt = "undefined" - host = "undefined" - semver = "undefined" - branch = "undefined" - uname = "undefined" - logger *zap.SugaredLogger - fastlog *zap.Logger - help = flag.Bool("help", false, "show usage") - scheme = map[bool]string{ + version = "undefined" + builddt = "undefined" + host = "undefined" + semver = "undefined" + branch = "undefined" + uname = "undefined" + logger *zap.SugaredLogger + fastlog *zap.Logger + showVersion = flag.Bool("version", false, "display version and exit") + help = flag.Bool("help", false, "show usage") + scheme = map[bool]string{ false: "http", true: "https", } @@ -103,6 +105,11 @@ func configure() { os.Exit(1) } + if *showVersion { + fmt.Printf("%s\n", semver) + os.Exit(0) + } + cfg.Templates = templatesFs cfg.Defaults = defaultsFs From e553b21b5e58d36ed56ca9d04f4dcb6499e61a86 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 7 Aug 2021 00:11:24 -0700 Subject: [PATCH 600/736] fix #408 add semicolons to auth_request_set --- examples/OpenResty/conf.d/app1.yourdomain.com.conf | 2 +- examples/OpenResty/conf.d/app2.yourdomain.com.conf | 2 +- examples/nginx/multi-file/conf.d/app1.yourdomain.com.conf | 2 +- examples/nginx/multi-file/conf.d/app2.yourdomain.com.conf | 2 +- examples/nginx/single-file/nginx_basic.conf | 2 +- examples/nginx/single-file/nginx_with_vouch.conf | 2 +- examples/nginx/single-file/nginx_with_vouch_single_server.conf | 2 +- examples/nginx/single-file/nginx_with_vouch_ssl.conf | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/OpenResty/conf.d/app1.yourdomain.com.conf b/examples/OpenResty/conf.d/app1.yourdomain.com.conf index 80c886bf..911e2d1a 100644 --- a/examples/OpenResty/conf.d/app1.yourdomain.com.conf +++ b/examples/OpenResty/conf.d/app1.yourdomain.com.conf @@ -49,7 +49,7 @@ server { location / { proxy_pass http://app1-private.yourdomain.com:8080; # may need to set - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; diff --git a/examples/OpenResty/conf.d/app2.yourdomain.com.conf b/examples/OpenResty/conf.d/app2.yourdomain.com.conf index 00be6e8b..dfc464b1 100644 --- a/examples/OpenResty/conf.d/app2.yourdomain.com.conf +++ b/examples/OpenResty/conf.d/app2.yourdomain.com.conf @@ -49,7 +49,7 @@ server { location / { proxy_pass http://app2-private.yourdomain.com:8080; # may need to set - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; diff --git a/examples/nginx/multi-file/conf.d/app1.yourdomain.com.conf b/examples/nginx/multi-file/conf.d/app1.yourdomain.com.conf index 584ef8fd..e208c328 100644 --- a/examples/nginx/multi-file/conf.d/app1.yourdomain.com.conf +++ b/examples/nginx/multi-file/conf.d/app1.yourdomain.com.conf @@ -41,7 +41,7 @@ server { location / { proxy_pass http://app1.yourdomain.com:8080; # may need to set - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # in this bock as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 # set user header (usually an email) proxy_set_header X-Vouch-User $auth_resp_x_vouch_user; diff --git a/examples/nginx/multi-file/conf.d/app2.yourdomain.com.conf b/examples/nginx/multi-file/conf.d/app2.yourdomain.com.conf index b7ce7c38..3bbb65be 100644 --- a/examples/nginx/multi-file/conf.d/app2.yourdomain.com.conf +++ b/examples/nginx/multi-file/conf.d/app2.yourdomain.com.conf @@ -41,7 +41,7 @@ server { location / { proxy_pass http://app2.yourdomain.com:8080; # may need to set - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # in this bock as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 # set user header (usually an email) proxy_set_header X-Vouch-User $auth_resp_x_vouch_user; diff --git a/examples/nginx/single-file/nginx_basic.conf b/examples/nginx/single-file/nginx_basic.conf index cb7ebb41..285aea4d 100644 --- a/examples/nginx/single-file/nginx_basic.conf +++ b/examples/nginx/single-file/nginx_basic.conf @@ -71,7 +71,7 @@ http { # forward authorized requests to your service protectedapp.yourdomain.com proxy_pass http://127.0.0.1:8080; # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; diff --git a/examples/nginx/single-file/nginx_with_vouch.conf b/examples/nginx/single-file/nginx_with_vouch.conf index 342507ed..72207164 100644 --- a/examples/nginx/single-file/nginx_with_vouch.conf +++ b/examples/nginx/single-file/nginx_with_vouch.conf @@ -70,7 +70,7 @@ http { # forward authorized requests to your service protectedapp.yourdomain.com proxy_pass http://127.0.0.1:8080; # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; diff --git a/examples/nginx/single-file/nginx_with_vouch_single_server.conf b/examples/nginx/single-file/nginx_with_vouch_single_server.conf index edee80a8..e0cfb292 100644 --- a/examples/nginx/single-file/nginx_with_vouch_single_server.conf +++ b/examples/nginx/single-file/nginx_with_vouch_single_server.conf @@ -81,7 +81,7 @@ http { # forward authorized requests to your service protectedapp.yourdomain.com proxy_pass http://127.0.0.1:8080; # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; diff --git a/examples/nginx/single-file/nginx_with_vouch_ssl.conf b/examples/nginx/single-file/nginx_with_vouch_ssl.conf index ce55ee05..8e9cb0c3 100644 --- a/examples/nginx/single-file/nginx_with_vouch_ssl.conf +++ b/examples/nginx/single-file/nginx_with_vouch_ssl.conf @@ -69,7 +69,7 @@ http { # forward authorized requests to your service protectedapp.yourdomain.com proxy_pass http://127.0.0.1:8080; # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; From dd9c0e1f04dcaf2b248f985b1b8f5f4a850dac60 Mon Sep 17 00:00:00 2001 From: Chirag Patel <46502305+cpatel-secureauth@users.noreply.github.com> Date: Wed, 18 Aug 2021 14:01:34 -0400 Subject: [PATCH 601/736] Update README.md Adding SecureAuth in the list as I have tested successfully with SecureAuth IDP --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5db2ab96..abc151df 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... +- SecureAuth - Google - [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) - GitHub Enterprise From 63c05d5d8cefe2a9d8c2303629ce1641d7365291 Mon Sep 17 00:00:00 2001 From: Chirag Patel <46502305+cpatel-secureauth@users.noreply.github.com> Date: Wed, 18 Aug 2021 14:20:58 -0400 Subject: [PATCH 602/736] Update README.md Adding OpenID Connect and OAuth 2.0 configuration document link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abc151df..35967c95 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... -- SecureAuth +- [SecureAuth](https://docs.secureauth.com/2104/en/openid-connect-and-oauth-2-0-configuration.html) - Google - [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) - GitHub Enterprise From 634f89fec760471fd396deeb1af067c8f6e41e4a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 18 Aug 2021 12:28:06 -0700 Subject: [PATCH 603/736] #359 link to node.js example from the README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5db2ab96..51f64b04 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ All Vouch Proxy configuration items are documented in [config/config.yml_example - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) - [FreeBSD support](https://github.com/vouch/vouch-proxy/issues/368) - [systemd startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) +- [using Node.js instead of Nginx to route requests](https://github.com/vouch/vouch-proxy/issues/359) Please do help us to expand this list. From 63f36bc2be120fa8cc9d56697bf9cce9d3878a1f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 18 Aug 2021 12:35:23 -0700 Subject: [PATCH 604/736] X-Vouch-IdP-Claims minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51f64b04..0329d4d5 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ The VP cookie may be split into several cookies to accomdate browser cookie size 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` 1. log in and call the `/validate` endpoint in a modern browser - 2. check the response headers for headers of the form `X-Vouch-Idp-Claims-` + 2. check the response headers for headers of the form `X-Vouch-IdP-Claims-` 3. If they are not there clear your cookies and cached browser data 4. 🐞 If they are still not there but exist in the jwt (esp. custom claims) there might be a bug 5. remove the `idtoken: X-Vouch-IdP-IdToken` from the `headers` section of vouch-proxy's `config.yml` if you don't need it From 446b18dd59e7cd44c98f5fe500490d3d6c8805ce Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 19 Aug 2021 16:56:42 -0700 Subject: [PATCH 605/736] Discord example from @eltariel --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0329d4d5..33251958 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) - [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) +- [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) - Keycloak - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) From 8ce0c492966424d3072586a3613e5b97dcc36744 Mon Sep 17 00:00:00 2001 From: Chirag Patel <46502305+cpatel-secureauth@users.noreply.github.com> Date: Fri, 20 Aug 2021 10:31:18 -0400 Subject: [PATCH 606/736] Adding config example for SecureAuth --- config/config.yml_example_secureauth | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 config/config.yml_example_secureauth diff --git a/config/config.yml_example_secureauth b/config/config.yml_example_secureauth new file mode 100644 index 00000000..b9f2f0a1 --- /dev/null +++ b/config/config.yml_example_secureauth @@ -0,0 +1,59 @@ + +# vouch config +# bare minimum to get vouch running with SecureAuth OpenID Connect + +vouch: + logLevel: debug + testing: false + listen: 0.0.0.0 # VOUCH_LISTEN + port: 9090 # VOUCH_PORT + + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + #- domain.com + + # - OR - + + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # and set vouch.cookie.domain to the domain you wish to protect + + allowAllUsers: true + + jwt: + # This issuer value should be match with SecureAuth OpenID configuration on Post Auth tab. + issuer: XXXXXXXXXXXXXXXXXXX + compress: false + + headers: + accesstoken: X-Vouch-IdP-AccessToken + idtoken: X-Vouch-IdP-IdToken + claims: + - sub + - name + - email + + cookie: + + # Cookie name can be set anything you want + # Extract value of this cookie to get accesstoken and idtoken. + + name: SecureAuth-Vouch + secure: true + domain: domain.com + +oauth: + # SecureAuth OpenID Connect + provider: oidc + client_id: XXXXXXXXXXXXXXX + client_secret: XXXXXXXXXXXXXXXXXXXXXX + auth_url: https:///SecureAuth/SecureAuth.aspx + token_url: https:///SecureAuth/OidcToken.aspx + user_info_url: https:///SecureAuth/OidcUserInfo.aspx + scopes: + - openid + - email + - profile + # This callback_url need to set on SecureAuth Post Auth tab as a redirect url. + callback_url: https://./auth From 56418db8731a640c998292779053fcedf6e0ac0b Mon Sep 17 00:00:00 2001 From: Chirag Patel <46502305+cpatel-secureauth@users.noreply.github.com> Date: Fri, 20 Aug 2021 10:34:45 -0400 Subject: [PATCH 607/736] Update README.md Adding link for SecureAuth config example. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35967c95..57e1d245 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... -- [SecureAuth](https://docs.secureauth.com/2104/en/openid-connect-and-oauth-2-0-configuration.html) +- [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - Google - [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) - GitHub Enterprise From bbc10b7117df44f2dbadfe91548a222416f54e2e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 21 Aug 2021 11:16:25 -0700 Subject: [PATCH 608/736] adjust SecureAuth entry for brevity and clarity --- README.md | 2 +- config/config.yml_example_secureauth | 45 +++++----------------------- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 57e1d245..28181e07 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... -- [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - Google - [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) - GitHub Enterprise @@ -21,6 +20,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) - [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) +- [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) - Keycloak - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) diff --git a/config/config.yml_example_secureauth b/config/config.yml_example_secureauth index b9f2f0a1..edb11b44 100644 --- a/config/config.yml_example_secureauth +++ b/config/config.yml_example_secureauth @@ -3,45 +3,16 @@ # bare minimum to get vouch running with SecureAuth OpenID Connect vouch: - logLevel: debug - testing: false - listen: 0.0.0.0 # VOUCH_LISTEN - port: 9090 # VOUCH_PORT - - # valid domains that the jwt cookies can be set into - # the callback_urls will be to these domains domains: - #- domain.com - - # - OR - - - # instead of setting specific domains you may prefer to allow all users... - # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider - # and set vouch.cookie.domain to the domain you wish to protect - - allowAllUsers: true - - jwt: - # This issuer value should be match with SecureAuth OpenID configuration on Post Auth tab. - issuer: XXXXXXXXXXXXXXXXXXX - compress: false - - headers: - accesstoken: X-Vouch-IdP-AccessToken - idtoken: X-Vouch-IdP-IdToken - claims: - - sub - - name - - email - - cookie: + - yourdomain.com - # Cookie name can be set anything you want - # Extract value of this cookie to get accesstoken and idtoken. + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea + # allowAllUsers: true - name: SecureAuth-Vouch - secure: true - domain: domain.com + # cookie: + # secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com oauth: # SecureAuth OpenID Connect @@ -55,5 +26,5 @@ oauth: - openid - email - profile - # This callback_url need to set on SecureAuth Post Auth tab as a redirect url. + # callback_url needs to be set as a "redirect url" on the SecureAuth Post Auth tab callback_url: https://./auth From 4901f6cd3c4b78ee929c5d29fbabdec2a45b5ed5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 21 Aug 2021 11:23:32 -0700 Subject: [PATCH 609/736] include CHANGELOG in "Contributing" --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a631abfe..e4848305 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,7 @@ A bug report can be generated from a docker environment using the `quay.io/vouch docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh quay.io/vouch/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret ``` -### submitting a Pull Request for a new feature +### Contributing to Vouch Proxy by submitting a Pull Request I really love Vouch Proxy! I wish it did XXXX... @@ -426,6 +426,7 @@ Please make a proposal before you spend your time and our time integrating a new Code contributions should.. - include unit tests and in some cases end-to-end tests +- include an entry at the top of CHANGELOG.md in the **Unreleased** section - be formatted with `go fmt`, checked with `go vet` and other common go tools - not break existing setups without a clear reason (usually security related) - and generally be discussed beforehand in a GitHub issue From 428cda64d5522c8e2de8053174a3663d8bd96d20 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 27 Aug 2021 19:34:59 -0700 Subject: [PATCH 610/736] #373 set `vouch.document_root` for "vouch in a path" --- .defaults.yml | 1 + CHANGELOG.md | 4 + README.md | 41 ++++++++ config/config.yml_example | 3 + .../handler_login_url_document_root.yml | 17 ++++ handlers/auth.go | 5 +- handlers/auth_test.go | 95 +++++++++++++++++++ handlers/login.go | 2 +- handlers/login_test.go | 52 ++++++++++ main.go | 23 +++-- pkg/cfg/cfg.go | 1 + pkg/cfg/cfg_test.go | 4 +- pkg/responses/responses.go | 9 +- templates/index.tmpl | 12 +-- 14 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 config/testing/handler_login_url_document_root.yml create mode 100644 handlers/auth_test.go diff --git a/.defaults.yml b/.defaults.yml index 55f74827..43b8bdf8 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -9,6 +9,7 @@ vouch: testing: false listen: 0.0.0.0 port: 9090 + # document_root: # domains: allowAllUsers: false publicAccess: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 769f6da2..6a88a96e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.33.0 + +- [Vouch Proxy running in a path](https://github.com/vouch/vouch-proxy/issues/373) + ## v0.32.0 - [slack oidc example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_slack) and [slack app manifest](https://github.com/vouch/vouch-proxy/blob/master/examples/slack/vouch-slack-oidc-app-manifest.yml) diff --git a/README.md b/README.md index e4848305..e08dc1f1 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,47 @@ server { } ``` +### Vouch Proxy "in a path" + +As of `v0.33.0` Vouch Proxy can be served within an Nginx location (path) by configuring `vouch.document_root: /vp_in_a_path` + +This avoids the need to setup a separate domain for Vouch Proxy such as `vouch.yourdomain.com`. For example VP login will be served from https://protectedapp.yourdomain.com/vp_in_a_path/login + +```{.nginxconf} +server { + listen 443 ssl http2; + server_name protectedapp.yourdomain.com; + + ssl_certificate /etc/letsencrypt/live/protectedapp.yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/protectedapp.yourdomain.com/privkey.pem; + + # This location serves all Vouch Proxy endpoints as /vp_in_a_path/$uri + # including /vp_in_a_path/validate, /vp_in_a_path/login, /vp_in_a_path/logout, /vp_in_a_path/auth, /vp_in_a_path/auth/$STATE, etc + location /vp_in_a_path { + proxy_pass http://127.0.0.1:9090; # must not! have a slash at the end + proxy_set_header Host $http_host; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + } + + # if /vp_in_a_path/validate returns `401 not authorized` then forward the request to the error401block + error_page 401 = @error401; + + location @error401 { + # redirect to Vouch Proxy for login + return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount + } + + location / { + auth_request /vp_in_a_path/validate; + proxy_pass http://127.0.0.1:8080; + # see the Nginx config above for additional headers which can be set from Vouch Proxy + } + +``` + +### Additional Nginx Configurations + Additional Nginx configurations can be found in the [examples](https://github.com/vouch/vouch-proxy/tree/master/examples) directory. ## Configuring Vouch Proxy using Environmental Variables diff --git a/config/config.yml_example b/config/config.yml_example index a9eef07e..80bebd02 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -20,6 +20,9 @@ vouch: listen: 0.0.0.0 # VOUCH_LISTEN port: 9090 # VOUCH_PORT + # document_root - VOUCH_DOCUMENT_ROOT + # see README for " + # domains - VOUCH_DOMAINS # each of these domains must serve the url https://vouch.$domains[0] https://vouch.$domains[1] ... # so that the cookie which stores the JWT can be set in the relevant domain diff --git a/config/testing/handler_login_url_document_root.yml b/config/testing/handler_login_url_document_root.yml new file mode 100644 index 00000000..27be44bc --- /dev/null +++ b/config/testing/handler_login_url_document_root.yml @@ -0,0 +1,17 @@ +vouch: + document_root: /vouch_in_a_path + domains: + - example.com + + cookie: + secure: false + domain: example.com + + jwt: + secret: testingsecret + +oauth: + provider: google + client_id: http://vouch.github.io + auth_url: https://indielogin.com/auth + callback_url: http://vouch.github.io:9090/auth diff --git a/handlers/auth.go b/handlers/auth.go index 1594053a..dcfd69ef 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -42,10 +42,11 @@ func CallbackHandler(w http.ResponseWriter, r *http.Request) { responses.Error400(w, r, fmt.Errorf("/auth: could not find state in query %s", r.URL.RawQuery)) return } + // has to have a trailing / in its path, because the path of the session cookie is set to /auth/{state}/. - authStateURL := fmt.Sprintf("/auth/%s/?%s", queryState, r.URL.RawQuery) + // see note in login.go and https://github.com/vouch/vouch-proxy/issues/373 + authStateURL := fmt.Sprintf("%s/auth/%s/?%s", cfg.Cfg.DocumentRoot, queryState, r.URL.RawQuery) responses.Redirect302(w, r, authStateURL) - } // AuthStateHandler /auth/{state}/ diff --git a/handlers/auth_test.go b/handlers/auth_test.go new file mode 100644 index 00000000..2846c504 --- /dev/null +++ b/handlers/auth_test.go @@ -0,0 +1,95 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package handlers + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vouch/vouch-proxy/pkg/cfg" +) + +func TestCallbackHandlerDocumentRoot(t *testing.T) { + handlerL := http.HandlerFunc(LoginHandler) + handlerA := http.HandlerFunc(CallbackHandler) + + tests := []struct { + name string + configFile string + wantcode int + }{ + {"should have URL that begins with DocumentRoot", "/config/testing/handler_login_url_document_root.yml", http.StatusFound}, + {"should have URL that does not begin with DocumentRoot", "/config/testing/handler_login_url.yml", http.StatusFound}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setUp(tt.configFile) + + // first make a request of /login to set the session cookie + reqLogin, err := http.NewRequest("GET", cfg.Cfg.DocumentRoot+"/login?url=http://myapp.example.com/logout", nil) + reqLogin.Header.Set("Host", "my.example.com") + if err != nil { + t.Fatal(err) + } + rrL := httptest.NewRecorder() + handlerL.ServeHTTP(rrL, reqLogin) + + // grab the state from the session cookie to + session, err := sessstore.Get(reqLogin, cfg.Cfg.Session.Name) + state := session.Values["state"].(string) + + // now mimic an IdP returning the state variable back to us + reqAuth, err := http.NewRequest("GET", cfg.Cfg.DocumentRoot+"/auth?state="+state, nil) + reqAuth.Header.Set("Host", "my.example.com") + if err != nil { + t.Fatal(err) + } + // transfer the cookie from rrL to reqAuth + rrA := httptest.NewRecorder() + + handlerA.ServeHTTP(rrA, reqAuth) + if rrA.Code != tt.wantcode { + t.Errorf("LoginHandler() status = %v, want %v", rrA.Code, tt.wantcode) + } + + // confirm the requst to $DocumentRoot/auth is redirected to $DocumentRoot/auth/$state + redirectURL, err := url.Parse(rrA.Header()["Location"][0]) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, fmt.Sprintf("%s/auth/%s/", cfg.Cfg.DocumentRoot, state), redirectURL.Path) + + }) + } +} + +func TestAuthStateHandler(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + tests := []struct { + name string + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + AuthStateHandler(tt.args.w, tt.args.r) + }) + } +} diff --git a/handlers/login.go b/handlers/login.go index a7ff8f3b..462a4f7f 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -55,7 +55,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { // set the path for the session cookie to only send the correct cookie to /auth/{state}/ // must have a trailing slash. Otherwise, it is send to all endpoints that _start_ with the cookie path. - session.Options.Path = fmt.Sprintf("/auth/%s/", state) + session.Options.Path = fmt.Sprintf("%s/auth/%s/", cfg.Cfg.DocumentRoot, state) log.Debugf("session state set to %s", session.Values["state"]) diff --git a/handlers/login_test.go b/handlers/login_test.go index 240e1a4a..71f519a9 100644 --- a/handlers/login_test.go +++ b/handlers/login_test.go @@ -14,6 +14,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "strings" "testing" "github.com/google/go-cmp/cmp" @@ -128,6 +129,57 @@ func Test_getValidRequestedURL(t *testing.T) { } } +func TestLoginHandlerDocumentRoot(t *testing.T) { + handler := http.HandlerFunc(LoginHandler) + + tests := []struct { + name string + configFile string + wantcode int + }{ + {"general test", "/config/testing/handler_login_url_document_root.yml", http.StatusFound}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setUp(tt.configFile) + + req, err := http.NewRequest("GET", cfg.Cfg.DocumentRoot+"/logout?url=http://myapp.example.com/login", nil) + req.Header.Set("Host", "my.example.com") + if err != nil { + t.Fatal(err) + } + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + if rr.Code != tt.wantcode { + t.Errorf("LogoutHandler() status = %v, want %v", rr.Code, tt.wantcode) + } + + found := false + for _, c := range rr.Result().Cookies() { + if c.Name == cfg.Cfg.Session.Name { + if strings.HasPrefix(c.Path, cfg.Cfg.DocumentRoot+"/auth") { + found = true + } + } + } + if !found { + t.Errorf("session cookie is not set into path that begins with Cfg.DocumentRoot %s", cfg.Cfg.DocumentRoot) + } + + // confirm the OAuthClient has a properly configured + redirectURL, err := url.Parse(rr.Header()["Location"][0]) + if err != nil { + t.Fatal(err) + } + redirectParam := redirectURL.Query().Get("redirect_uri") + assert.NotEmpty(t, cfg.OAuthClient.RedirectURL, "cfg.OAuthClient.RedirectURL is empty") + assert.NotEmpty(t, redirectParam, "redirect_uri should not be empty when redirected to google oauth") + + }) + } +} func TestLoginHandler(t *testing.T) { handler := http.HandlerFunc(LoginHandler) diff --git a/main.go b/main.go index 965e7603..d5e481f9 100644 --- a/main.go +++ b/main.go @@ -147,26 +147,31 @@ func main() { "semver", semver, "listen", scheme[tls]+"://"+listen, "tls", tls, + "document_root", cfg.Cfg.DocumentRoot, "oauth.provider", cfg.GenOAuth.Provider) // router := mux.NewRouter() router := httprouter.New() + if cfg.Cfg.DocumentRoot != "" { + logger.Debugf("adjusting all served URIs to be under %s", cfg.Cfg.DocumentRoot) + } + authH := http.HandlerFunc(handlers.ValidateRequestHandler) - router.HandlerFunc(http.MethodGet, "/validate", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) - router.HandlerFunc(http.MethodGet, "/_external-auth-:id", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/validate", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/_external-auth-:id", timelog.TimeLog(jwtmanager.JWTCacheHandler(authH))) loginH := http.HandlerFunc(handlers.LoginHandler) - router.HandlerFunc(http.MethodGet, "/login", timelog.TimeLog(loginH)) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/login", timelog.TimeLog(loginH)) logoutH := http.HandlerFunc(handlers.LogoutHandler) - router.HandlerFunc(http.MethodGet, "/logout", timelog.TimeLog(logoutH)) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/logout", timelog.TimeLog(logoutH)) callH := http.HandlerFunc(handlers.CallbackHandler) - router.HandlerFunc(http.MethodGet, "/auth/", timelog.TimeLog(callH)) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/auth", timelog.TimeLog(callH)) authStateH := http.HandlerFunc(handlers.AuthStateHandler) - router.HandlerFunc(http.MethodGet, "/auth/:state/", timelog.TimeLog(authStateH)) + router.HandlerFunc(http.MethodGet, cfg.Cfg.DocumentRoot+"/auth/:state/", timelog.TimeLog(authStateH)) healthH := http.HandlerFunc(handlers.HealthcheckHandler) router.HandlerFunc(http.MethodGet, "/healthcheck", timelog.TimeLog(healthH)) @@ -175,9 +180,9 @@ func main() { // router.ServeFiles("/static/*filepath", http.FS(staticFs)) // so instead we publish all three routes - router.Handler(http.MethodGet, "/static/css/main.css", http.FileServer(http.FS(staticFs))) - router.Handler(http.MethodGet, "/static/img/favicon.ico", http.FileServer(http.FS(staticFs))) - router.Handler(http.MethodGet, "/static/img/multicolor_V_500x500.png", http.FileServer(http.FS(staticFs))) + router.Handler(http.MethodGet, cfg.Cfg.DocumentRoot+"/static/css/main.css", http.StripPrefix(cfg.Cfg.DocumentRoot, http.FileServer(http.FS(staticFs)))) + router.Handler(http.MethodGet, cfg.Cfg.DocumentRoot+"/static/img/favicon.ico", http.StripPrefix(cfg.Cfg.DocumentRoot, http.FileServer(http.FS(staticFs)))) + router.Handler(http.MethodGet, cfg.Cfg.DocumentRoot+"/static/img/multicolor_V_500x500.png", http.StripPrefix(cfg.Cfg.DocumentRoot, http.FileServer(http.FS(staticFs)))) // this also works for static files // router.NotFound = http.FileServer(http.FS(staticFs)) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 6a5ad5ec..d462f207 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -44,6 +44,7 @@ type Config struct { LogLevel string `mapstructure:"logLevel"` Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` + DocumentRoot string `mapstructure:"document_root" envconfig:"document_root"` Domains []string `mapstructure:"domains"` WhiteList []string `mapstructure:"whitelist"` TeamWhiteList []string `mapstructure:"teamWhitelist"` diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 5b10f401..dc7ffb74 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -134,7 +134,7 @@ func Test_configureFromEnvCfg(t *testing.T) { senv := []string{"VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", - "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY"} + "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} // array of strings saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} // int @@ -171,7 +171,7 @@ func Test_configureFromEnvCfg(t *testing.T) { scfg := []string{Cfg.Listen, Cfg.JWT.Issuer, Cfg.JWT.Secret, Cfg.Headers.JWT, Cfg.Headers.User, Cfg.Headers.QueryString, Cfg.Headers.Redirect, Cfg.Headers.Success, Cfg.Headers.Error, Cfg.Headers.ClaimHeader, Cfg.Headers.AccessToken, Cfg.Headers.IDToken, Cfg.Cookie.Name, Cfg.Cookie.Domain, - Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, + Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, Cfg.DocumentRoot, } sacfg := [][]string{Cfg.Domains, Cfg.WhiteList, Cfg.TeamWhiteList, Cfg.Headers.Claims, Cfg.TestURLs, Cfg.LogoutRedirectURLs} diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 2ff29f3e..0373964b 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -23,9 +23,10 @@ import ( // Index variables passed to index.tmpl type Index struct { - Msg string - TestURLs []string - Testing bool + Msg string + TestURLs []string + Testing bool + DocumentRoot string } var ( @@ -48,7 +49,7 @@ func Configure() { // RenderIndex render the response as an HTML page, mostly used in testing func RenderIndex(w http.ResponseWriter, msg string) { - if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURLs: cfg.Cfg.TestURLs, Testing: cfg.Cfg.Testing}); err != nil { + if err := indexTemplate.Execute(w, &Index{Msg: msg, TestURLs: cfg.Cfg.TestURLs, Testing: cfg.Cfg.Testing, DocumentRoot: cfg.Cfg.DocumentRoot}); err != nil { log.Error(err) } } diff --git a/templates/index.tmpl b/templates/index.tmpl index dbfb4197..a8571b22 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -1,8 +1,8 @@ - - + + @@ -14,7 +14,7 @@ @@ -30,9 +30,9 @@ All 302 redirects will be captured and presented as links here
      -
    • login
    • -
    • logout
    • -
    • validate
    • +
    • login
    • +
    • logout
    • +
    • validate
    • {{ if .TestURLs }} {{ range $url := .TestURLs}}
    • {{ $url }}
    • From 45614c38375d24d6ffe2d7e662b3e10df483be1c Mon Sep 17 00:00:00 2001 From: Valentin Lahaye Date: Sat, 28 Aug 2021 10:11:42 +0200 Subject: [PATCH 611/736] Add OAuth ClaimsParameter support See also: #414 --- config/config.yml_example_twitch | 43 +++++++++++++++++++++ handlers/login.go | 2 +- pkg/cfg/oauth.go | 66 ++++++++++++++++++++++---------- 3 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 config/config.yml_example_twitch diff --git a/config/config.yml_example_twitch b/config/config.yml_example_twitch new file mode 100644 index 00000000..94fefbbe --- /dev/null +++ b/config/config.yml_example_twitch @@ -0,0 +1,43 @@ + +# vouch config +# bare minimum to get vouch running with Twitch + +vouch: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + - yourdomain.com + - yourotherdomain.com + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # and set vouch.cookie.domain to the domain you wish to protect + # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + # Generic OpenID Connect + # including okta + provider: oidc + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + auth_url: https://id.twitch.tv/oauth2/authorize + token_url: https://id.twitch.tv/oauth2/token + user_info_url: https://id.twitch.tv/oauth2/userinfo + scopes: + - openid + - user:read:email + claims: + userinfo: + email: + essential: true + email_verified: + essential: true + callback_url: https://vouch.yourdomain.com:9090/auth diff --git a/handlers/login.go b/handlers/login.go index a7ff8f3b..4028cd0a 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -274,7 +274,7 @@ func oauthLoginURL(r *http.Request, session sessions.Session) string { opts = append(opts, oauth2.SetAuthURLParam("code_challenge", session.Values["codeChallenge"].(string))) } if cfg.OAuthopts != nil { - opts = append(opts, cfg.OAuthopts) + opts = append(opts, cfg.OAuthopts...) } return cfg.OAuthClient.AuthCodeURL(state, opts...) } diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 913c6148..e75cd9cd 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -11,6 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( + "encoding/json" "errors" "fmt" "strings" @@ -29,7 +30,7 @@ var ( // this actually carries the oauth2 client ala oauthclient.Client(oauth2.NoContext, providerToken) OAuthClient *oauth2.Config // OAuthopts authentication options - OAuthopts oauth2.AuthCodeOption + OAuthopts []oauth2.AuthCodeOption // Providers static strings to test against Providers = &OAuthProviders{ @@ -64,28 +65,51 @@ type OAuthProviders struct { // `envconfig` tag is for env var support // https://github.com/kelseyhightower/envconfig type oauthConfig struct { - Provider string `mapstructure:"provider"` - ClientID string `mapstructure:"client_id" envconfig:"client_id"` - ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` - AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` - TokenURL string `mapstructure:"token_url" envconfig:"token_url"` - LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` - RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` - RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` - RelyingPartyId string `mapstructure:"relying_party_id" envconfig:"relying_party_id"` - Scopes []string `mapstructure:"scopes"` - UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` - UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` - UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` - PreferredDomain string `mapstructure:"preferredDomain"` - AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` - CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` + Provider string `mapstructure:"provider"` + ClientID string `mapstructure:"client_id" envconfig:"client_id"` + ClientSecret string `mapstructure:"client_secret" envconfig:"client_secret"` + AuthURL string `mapstructure:"auth_url" envconfig:"auth_url"` + TokenURL string `mapstructure:"token_url" envconfig:"token_url"` + LogoutURL string `mapstructure:"end_session_endpoint" envconfig:"end_session_endpoint"` + RedirectURL string `mapstructure:"callback_url" envconfig:"callback_url"` + RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` + RelyingPartyId string `mapstructure:"relying_party_id" envconfig:"relying_party_id"` + Scopes []string `mapstructure:"scopes"` + // pointer-to-pointer so that the default value is nil + Claims **oauthClaimsConfig `mapstructure:"claims"` + UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` + UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` + UserOrgURL string `mapstructure:"user_org_url" envconfig:"user_org_url"` + PreferredDomain string `mapstructure:"preferredDomain"` + AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` + CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` +} + +type oauthClaimsConfig struct { + UserInfo map[string]*oauthClaimValueConfig `mapstructure:"userinfo" json:"userinfo,omitempty"` + IDToken map[string]*oauthClaimValueConfig `mapstructure:"id_token" json:"id_token,omitempty"` +} + +type oauthClaimValueConfig struct { + Essential bool `mapstructure:"essential" json:"essential,omitempty"` + Value interface{} `mapstructure:"value" json:"value,omitempty"` + Values []interface{} `mapstructure:"values" json:"values,omitempty"` } func configureOauth() error { // OAuth defaults and client configuration - return UnmarshalKey("oauth", &GenOAuth) - + if err := UnmarshalKey("oauth", &GenOAuth); err != nil { + return err + } + if GenOAuth.Claims != nil { + claims, err := json.Marshal(GenOAuth.Claims) + if err != nil { + return err + } + log.Infof("setting OAuth param 'claims' to %s", claims) + OAuthopts = append(OAuthopts, oauth2.SetAuthURLParam("claims", string(claims))) + } + return nil } func oauthBasicTest() error { @@ -174,7 +198,7 @@ func setDefaultsGoogle() { } if GenOAuth.PreferredDomain != "" { log.Infof("setting Google OAuth preferred login domain param 'hd' to %s", GenOAuth.PreferredDomain) - OAuthopts = oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain) + OAuthopts = append(OAuthopts, oauth2.SetAuthURLParam("hd", GenOAuth.PreferredDomain)) } GenOAuth.CodeChallengeMethod = "S256" } @@ -186,7 +210,7 @@ func setDefaultsADFS() { GenOAuth.RelyingPartyId = GenOAuth.RedirectURL } - OAuthopts = oauth2.SetAuthURLParam("resource", GenOAuth.RelyingPartyId) + OAuthopts = append(OAuthopts, oauth2.SetAuthURLParam("resource", GenOAuth.RelyingPartyId)) } func setDefaultsAzure() { From 33d32dc7e4a62fdb12ad41ad5d38a6b017de2687 Mon Sep 17 00:00:00 2001 From: Valentin Lahaye Date: Sat, 28 Aug 2021 21:05:34 +0200 Subject: [PATCH 612/736] Add OAuth ClaimsParameter test, update configs and CHANGELOG --- CHANGELOG.md | 3 ++ config/config.yml_example | 19 ++++++++ config/testing/test_config_oauth_claims.yml | 48 +++++++++++++++++++++ pkg/cfg/oauth.go | 2 +- pkg/cfg/oauth_test.go | 10 +++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 config/testing/test_config_oauth_claims.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 769f6da2..a79f8863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +- add support for [the "claims" Request Parameter](https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) to support Twitch OIDC as IdP +- add [Twitch OIDC example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_twitch) + ## v0.32.0 - [slack oidc example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_slack) and [slack app manifest](https://github.com/vouch/vouch-proxy/blob/master/examples/slack/vouch-slack-oidc-app-manifest.yml) diff --git a/config/config.yml_example b/config/config.yml_example index a9eef07e..99d56c93 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -249,6 +249,25 @@ oauth: - openid - email - profile + # optionally set the "claims" request parameter (see https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) + # resolves issue https://github.com/vouch/vouch-proxy/issues/414 + # claims: + # userinfo: + # given_name: + # essential: true + # nickname: null + # email: + # essential: true + # email_verified: + # essential: true + # picture: null + # "http://example.info/claims/groups": null + # id_token: + # auth_time: + # essential: true + # acr: + # values: + # - "urn:mace:incommon:iap:silver" callback_url: http://vouch.yourdomain.com:9090/auth # PKCE method if enabled, S256 is currently supported (check https://www.oauth.com/oauth2-servers/pkce/) # resolves issue https://github.com/vouch/vouch-proxy/issues/303 diff --git a/config/testing/test_config_oauth_claims.yml b/config/testing/test_config_oauth_claims.yml new file mode 100644 index 00000000..8ccf03de --- /dev/null +++ b/config/testing/test_config_oauth_claims.yml @@ -0,0 +1,48 @@ +vouch: + logLevel: debug + listen: 0.0.0.0 + port: 9090 + domains: + - vouch.github.io + + whiteList: + - bob@yourdomain.com + - alice@yourdomain.com + - joe@yourdomain.com + + cookie: + name: vouchTestingCookie + + session: + name: VouchTestingSession + + jwt: + secret: testingsecret + +oauth: + provider: oidc + auth_url: https://oauth2.example.info/authorize + token_url: https://oauth2.example.info/token + user_info_url: https://oauth2.example.info/userinfo + scopes: + - openid + - email + - profile + claims: + userinfo: + given_name: + essential: true + nickname: null + email: + essential: true + email_verified: + essential: true + picture: null + "http://example.info/claims/groups": null + id_token: + auth_time: + essential: true + acr: + values: + - "urn:mace:incommon:iap:silver" + callback_url: https://vouch.yourdomain.com:9090/auth diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index e75cd9cd..f22faed0 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -75,7 +75,7 @@ type oauthConfig struct { RedirectURLs []string `mapstructure:"callback_urls" envconfig:"callback_urls"` RelyingPartyId string `mapstructure:"relying_party_id" envconfig:"relying_party_id"` Scopes []string `mapstructure:"scopes"` - // pointer-to-pointer so that the default value is nil + // pointer-to-pointer so that the default uninitialized value is nil Claims **oauthClaimsConfig `mapstructure:"claims"` UserInfoURL string `mapstructure:"user_info_url" envconfig:"user_info_url"` UserTeamURL string `mapstructure:"user_team_url" envconfig:"user_team_url"` diff --git a/pkg/cfg/oauth_test.go b/pkg/cfg/oauth_test.go index 8a5d038b..055d5648 100644 --- a/pkg/cfg/oauth_test.go +++ b/pkg/cfg/oauth_test.go @@ -11,7 +11,10 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( + "net/url" "testing" + + "github.com/stretchr/testify/assert" ) func Test_checkCallbackConfig(t *testing.T) { @@ -33,3 +36,10 @@ func Test_checkCallbackConfig(t *testing.T) { }) } } + +func Test_configureOAuthWithClaims(t *testing.T) { + setUp("/config/testing/test_config_oauth_claims.yml") + authCodeURL, err := url.Parse(OAuthClient.AuthCodeURL("state", OAuthopts...)) + assert.Nil(t, err) + assert.Equal(t, authCodeURL.Query().Get("claims"), `{"userinfo":{"email":{"essential":true},"email_verified":{"essential":true},"given_name":{"essential":true},"http://example.info/claims/groups":null,"nickname":null,"picture":null},"id_token":{"acr":{"values":["urn:mace:incommon:iap:silver"]},"auth_time":{"essential":true}}}`) +} From 5e819a06b26a0683d01440bb1e4b34a506a29f60 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 30 Aug 2021 14:34:45 -0700 Subject: [PATCH 613/736] #373 VP "in a path" --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e08dc1f1..6b3c2a20 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim --- -## What Vouch Proxy Does... +## What Vouch Proxy Does Vouch Proxy (VP) forces visitors to login and authenticate with an [IdP](https://en.wikipedia.org/wiki/Identity_provider) (such as one of the services listed above) before allowing them access to a website. @@ -181,7 +181,7 @@ server { As of `v0.33.0` Vouch Proxy can be served within an Nginx location (path) by configuring `vouch.document_root: /vp_in_a_path` -This avoids the need to setup a separate domain for Vouch Proxy such as `vouch.yourdomain.com`. For example VP login will be served from https://protectedapp.yourdomain.com/vp_in_a_path/login +This avoids the need to setup a separate domain for Vouch Proxy such as `vouch.yourdomain.com`. For example VP login will be served from `https://protectedapp.yourdomain.com/vp_in_a_path/login` ```{.nginxconf} server { @@ -198,6 +198,11 @@ server { proxy_set_header Host $http_host; proxy_pass_request_body off; proxy_set_header Content-Length ""; + + # these return values are used by the @error401 call + auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt; + auth_request_set $auth_resp_err $upstream_http_x_vouch_err; + auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount; } # if /vp_in_a_path/validate returns `401 not authorized` then forward the request to the error401block @@ -205,7 +210,7 @@ server { location @error401 { # redirect to Vouch Proxy for login - return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount + return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err } location / { @@ -273,7 +278,7 @@ The VP cookie may be split into several cookies to accomdate browser cookie size 1. set `idtoken: X-Vouch-IdP-IdToken` in the `headers` section of vouch-proxy's `config.yml` 2. log in and call the `/validate` endpoint in a modern browser 3. check the response header for a `X-Vouch-IdP-IdToken` header - 4. copy the value of the header into the debugger at https://jwt.io/ and ensure that the necessary claims are part of the jwt + 4. copy the value of the header into the debugger at [https://jwt.io/](https://jwt.io/) and ensure that the necessary claims are part of the jwt 5. if they are not, you need to adjust the `scopes` in the `oauth` section of your `config.yml` or reconfigure your oauth provider 2. Set the necessary `claims` in the `header` section of the vouch-proxy `config.yml` 1. log in and call the `/validate` endpoint in a modern browser From 442b5a58fa41da509658689896b818309ffb8d1a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 30 Aug 2021 15:40:32 -0700 Subject: [PATCH 614/736] #414 support Twitch as OIDC IdP --- README.md | 34 +++++++++++++++++++------------- config/config.yml_example | 8 +++++--- config/config.yml_example_twitch | 6 +++--- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 6b3c2a20..cd6021a5 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ An SSO solution for Nginx using the [auth_request](http://nginx.org/en/docs/http Vouch Proxy supports many OAuth and OIDC login providers and can enforce authentication to... -- Google -- [GitHub](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/) -- GitHub Enterprise +- [Google](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_google) +- [GitHub](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_github) +- [GitHub Enterprise](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_github_enterprise) - [IndieAuth](https://indieauth.spec.indieweb.org/) - [Okta](https://developer.okta.com/blog/2018/08/28/nginx-auth-request) - [Slack](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_slack) @@ -20,6 +20,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Azure AD](https://github.com/vouch/vouch-proxy/issues/290) - [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) +- [Twitch](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_twitch) - [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) - [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) @@ -32,7 +33,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent Please do let us know when you have deployed Vouch Proxy with your preffered IdP or library so we can update the list. -If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be less than 1ms +If Vouch is running on the same host as the Nginx reverse proxy the response time from the `/validate` endpoint to Nginx should be **less than 1ms**. --- @@ -40,8 +41,10 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [What Vouch Proxy Does...](#what-vouch-proxy-does) - [Installation and Configuration](#installation-and-configuration) -- [Configuring Vouch Proxy using Environmental Variables](#configuring-vouch-proxy-using-environmental-variables) -- [More advanced configurations](#more-advanced-configurations) + - [Vouch Proxy "in a path"](#vouch-proxy-in-a-path) + - [Additional Nginx Configurations](#Additional Nginx Configurations) + - [Configuration via Environmental Variables](#configuring-via-environmental-variables) +- [Tips, Tricks and Advanced Configurations](#tips-tricks-and-advanced-configurations) - [Scopes and Claims](#scopes-and-claims) - [Running from Docker](#running-from-docker) - [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) @@ -225,9 +228,9 @@ server { Additional Nginx configurations can be found in the [examples](https://github.com/vouch/vouch-proxy/tree/master/examples) directory. -## Configuring Vouch Proxy using Environmental Variables +### Configuring via Environmental Variables -Here's a minimal setup using Google OAuth... +Here's a minimal setup using Google's OAuth... ```bash VOUCH_DOMAINS=yourdomain.com \ @@ -244,7 +247,7 @@ All lists with multiple values must be comma separated: `VOUCH_DOMAINS="yourdoma The variable `VOUCH_CONFIG` can be used to set an alternate location for the configuration file. `VOUCH_ROOT` can be used to set an alternate root directory for Vouch Proxy to look for support files. -## More advanced configurations +## Tips, Ticks and Advanced Configurations All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) @@ -438,7 +441,7 @@ TLDR: - set `vouch.testing: true` - set `vouch.logLevel: debug` -- conduct a full round trip of `./vouch-proxy` capturing the output.. +- conduct two full round trips of `./vouch-proxy` capturing the output.. - VP startup - `/validate` - `/login` - even if the error is here @@ -465,20 +468,23 @@ docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it -- ### Contributing to Vouch Proxy by submitting a Pull Request -I really love Vouch Proxy! I wish it did XXXX... +**_I really love Vouch Proxy! I wish it did XXXX..._** -Please make a proposal before you spend your time and our time integrating a new feature. +That's really wonderful and contributions are greatly appreciated. However, please search through the existing issues, both open and closed, to look for any prior work or conversation. Then please make a proposal before we all spend valuable time considering and integrating a new feature. Code contributions should.. +- generally be discussed beforehand in a GitHub issue - include unit tests and in some cases end-to-end tests -- include an entry at the top of CHANGELOG.md in the **Unreleased** section - be formatted with `go fmt`, checked with `go vet` and other common go tools +- accomodate configuration via `config.yml` as well as `ENVIRONMENT_VARIABLEs`. - not break existing setups without a clear reason (usually security related) -- and generally be discussed beforehand in a GitHub issue +- include an entry at the top of CHANGELOG.md in the **Unreleased** section For larger contributions or code related to a platform that we don't currently support we will ask you to commit to supporting the feature for an agreed upon period. Invariably someone will pop up here with a question and we want to be able to support these requests. +**Thank you to all of the contributors that have provided their time and effort and thought to improving VP.** + ## Advanced Authorization Using OpenResty OpenResty® is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies. diff --git a/config/config.yml_example b/config/config.yml_example index 0cabe8c0..5d4d2344 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -21,7 +21,8 @@ vouch: port: 9090 # VOUCH_PORT # document_root - VOUCH_DOCUMENT_ROOT - # see README for " + # see README for `Vouch Proxy "in a path"` - https://github.com/vouch/vouch-proxy#vouch-proxy-in-a-path + # document_root: vp_in_a_path # domains - VOUCH_DOMAINS # each of these domains must serve the url https://vouch.$domains[0] https://vouch.$domains[1] ... @@ -200,6 +201,7 @@ vouch: # preferreddomain: OAUTH_PREFERREDDOMAIN # callback_urls: OAUTH_CALLBACK_URLS # scopes: OAUTH_SCOPES +# claims: OAUTH_CLAIMS # code_challenge_method: OAUTH_CODE_CHALLENGE_METHOD # relying_party_id OAUTH_RELYING_PARTY_ID @@ -252,8 +254,9 @@ oauth: - openid - email - profile + callback_url: http://vouch.yourdomain.com:9090/auth # optionally set the "claims" request parameter (see https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) - # resolves issue https://github.com/vouch/vouch-proxy/issues/414 + # required by Twitch, resolves issue https://github.com/vouch/vouch-proxy/issues/414 # claims: # userinfo: # given_name: @@ -271,7 +274,6 @@ oauth: # acr: # values: # - "urn:mace:incommon:iap:silver" - callback_url: http://vouch.yourdomain.com:9090/auth # PKCE method if enabled, S256 is currently supported (check https://www.oauth.com/oauth2-servers/pkce/) # resolves issue https://github.com/vouch/vouch-proxy/issues/303 code_challenge_method: S256 diff --git a/config/config.yml_example_twitch b/config/config.yml_example_twitch index 94fefbbe..7faea26b 100644 --- a/config/config.yml_example_twitch +++ b/config/config.yml_example_twitch @@ -18,26 +18,26 @@ vouch: cookie: # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) - secure: false + # secure: false # vouch.cookie.domain must be set when enabling allowAllUsers # domain: yourdomain.com oauth: # Generic OpenID Connect - # including okta provider: oidc client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxx auth_url: https://id.twitch.tv/oauth2/authorize token_url: https://id.twitch.tv/oauth2/token user_info_url: https://id.twitch.tv/oauth2/userinfo + callback_url: https://vouch.yourdomain.com/auth scopes: - openid - user:read:email + # Twitch uses the claims parameter to configure the information returned via `user_info_url` claims: userinfo: email: essential: true email_verified: essential: true - callback_url: https://vouch.yourdomain.com:9090/auth From 589462bd9f66901d30dfa102a57895f2e73dfae2 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 30 Aug 2021 15:46:22 -0700 Subject: [PATCH 615/736] vouch --> Vouch Proxy --- config/config.yml_example | 2 +- config/config.yml_example_adfs | 4 ++-- config/config.yml_example_azure | 4 ++-- config/config.yml_example_gitea | 4 ++-- config/config.yml_example_github | 4 ++-- config/config.yml_example_github_enterprise | 4 ++-- config/config.yml_example_google | 4 ++-- config/config.yml_example_homeassistant | 4 ++-- config/config.yml_example_indieauth | 4 ++-- config/config.yml_example_nextcloud | 4 ++-- config/config.yml_example_oidc | 4 ++-- config/config.yml_example_secureauth | 4 ++-- config/config.yml_example_slack | 4 ++-- config/config.yml_example_twitch | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/config/config.yml_example b/config/config.yml_example index 5d4d2344..ce9cbb04 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -1,4 +1,4 @@ -# vouch config +# Vouch Proxy configuration # you should probably start with one of the other example configs in this directory # Vouch Proxy does a fairly good job of setting its config to sane defaults diff --git a/config/config.yml_example_adfs b/config/config.yml_example_adfs index 785de684..03da4720 100644 --- a/config/config.yml_example_adfs +++ b/config/config.yml_example_adfs @@ -1,5 +1,5 @@ -# vouch config -# bare minimum to get vouch running with adfs +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with adfs vouch: # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate to ADFS diff --git a/config/config.yml_example_azure b/config/config.yml_example_azure index 541ac4c6..71496aa9 100644 --- a/config/config.yml_example_azure +++ b/config/config.yml_example_azure @@ -1,5 +1,5 @@ -# vouch config -# bare minimum to get vouch running with Azure AD +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Azure AD # https://github.com/vouch/vouch-proxy/issues/290 vouch: diff --git a/config/config.yml_example_gitea b/config/config.yml_example_gitea index 521bc987..532d530f 100644 --- a/config/config.yml_example_gitea +++ b/config/config.yml_example_gitea @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with Gitea +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Gitea vouch: domains: diff --git a/config/config.yml_example_github b/config/config.yml_example_github index 983a4686..281c9095 100644 --- a/config/config.yml_example_github +++ b/config/config.yml_example_github @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with github +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with github vouch: # domains: diff --git a/config/config.yml_example_github_enterprise b/config/config.yml_example_github_enterprise index f490d738..75463904 100644 --- a/config/config.yml_example_github_enterprise +++ b/config/config.yml_example_github_enterprise @@ -1,5 +1,5 @@ -# vouch config -# bare minimum to get vouch running with github enterprise +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with github enterprise # see config.yml_example for all options vouch: diff --git a/config/config.yml_example_google b/config/config.yml_example_google index 548129b4..9dd3dd81 100644 --- a/config/config.yml_example_google +++ b/config/config.yml_example_google @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with google +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with google vouch: domains: diff --git a/config/config.yml_example_homeassistant b/config/config.yml_example_homeassistant index 730c6de5..bbe860e2 100644 --- a/config/config.yml_example_homeassistant +++ b/config/config.yml_example_homeassistant @@ -1,5 +1,5 @@ -# vouch config -# bare minimum to get vouch running with HomeAssistant +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with HomeAssistant vouch: # logLevel: debug diff --git a/config/config.yml_example_indieauth b/config/config.yml_example_indieauth index 09a7e839..b229ce65 100644 --- a/config/config.yml_example_indieauth +++ b/config/config.yml_example_indieauth @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with IndieAuth +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with IndieAuth vouch: # domains: diff --git a/config/config.yml_example_nextcloud b/config/config.yml_example_nextcloud index cc9142c1..349c8457 100644 --- a/config/config.yml_example_nextcloud +++ b/config/config.yml_example_nextcloud @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with Nextcloud Authentication +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Nextcloud Authentication vouch: # domains: diff --git a/config/config.yml_example_oidc b/config/config.yml_example_oidc index 066dea41..8e99bdfb 100644 --- a/config/config.yml_example_oidc +++ b/config/config.yml_example_oidc @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with OpenID Connect (such as okta) +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with OpenID Connect (such as okta) vouch: # domains: diff --git a/config/config.yml_example_secureauth b/config/config.yml_example_secureauth index edb11b44..3f22572b 100644 --- a/config/config.yml_example_secureauth +++ b/config/config.yml_example_secureauth @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with SecureAuth OpenID Connect +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with SecureAuth OpenID Connect vouch: domains: diff --git a/config/config.yml_example_slack b/config/config.yml_example_slack index b478b7cc..e9286982 100644 --- a/config/config.yml_example_slack +++ b/config/config.yml_example_slack @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with Slack +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Slack vouch: domains: diff --git a/config/config.yml_example_twitch b/config/config.yml_example_twitch index 7faea26b..98e61bf9 100644 --- a/config/config.yml_example_twitch +++ b/config/config.yml_example_twitch @@ -1,6 +1,6 @@ -# vouch config -# bare minimum to get vouch running with Twitch +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Twitch vouch: # domains: From 6ca347be891ac4f514a83305a6711f29640ff1dd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 30 Aug 2021 15:58:01 -0700 Subject: [PATCH 616/736] fix Table of Contents links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cd6021a5..5a9eccaf 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [What Vouch Proxy Does...](#what-vouch-proxy-does) - [Installation and Configuration](#installation-and-configuration) - [Vouch Proxy "in a path"](#vouch-proxy-in-a-path) - - [Additional Nginx Configurations](#Additional Nginx Configurations) + - [Additional Nginx Configurations](#additional-nginx-configurations) - [Configuration via Environmental Variables](#configuring-via-environmental-variables) - [Tips, Tricks and Advanced Configurations](#tips-tricks-and-advanced-configurations) - [Scopes and Claims](#scopes-and-claims) @@ -50,7 +50,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) - [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) - [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) -- [Troubleshooting, Support and Feature Requests](#troubleshooting--support-and-feature-requests--read-this-before-submitting-an-issue-at-github-) +- [Troubleshooting, Support and Feature Requests](#troubleshooting-support-and-feature-requests-read-this-before-submitting-an-issue-at-github) (Read this before submitting an issue at GitHub) - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) @@ -247,7 +247,7 @@ All lists with multiple values must be comma separated: `VOUCH_DOMAINS="yourdoma The variable `VOUCH_CONFIG` can be used to set an alternate location for the configuration file. `VOUCH_ROOT` can be used to set an alternate root directory for Vouch Proxy to look for support files. -## Tips, Ticks and Advanced Configurations +## Tips, Tricks and Advanced Configurations All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) From 10ed96b97ddbcafcbffdd8b43763d156fe3c73f6 Mon Sep 17 00:00:00 2001 From: Fran Kelava Date: Tue, 7 Sep 2021 22:16:34 +0200 Subject: [PATCH 617/736] No longer require UserInfoURL to be set for Azure (#417) --- pkg/cfg/oauth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index f22faed0..79b033aa 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -137,8 +137,8 @@ func oauthBasicTest() error { case GenOAuth.Provider != Providers.Google && GenOAuth.AuthURL == "": // everyone except IndieAuth and Google has an authURL return errors.New("configuration error: oauth.auth_url not found") - case GenOAuth.Provider != Providers.Google && GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.HomeAssistant && GenOAuth.Provider != Providers.ADFS && GenOAuth.UserInfoURL == "": - // everyone except IndieAuth, Google and ADFS has an userInfoURL + case GenOAuth.Provider != Providers.Google && GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.HomeAssistant && GenOAuth.Provider != Providers.ADFS && GenOAuth.Provider != Providers.Azure && GenOAuth.UserInfoURL == "": + // everyone except IndieAuth, Google and ADFS has an userInfoURL, and Azure does not actively use it return errors.New("configuration error: oauth.user_info_url not found") case GenOAuth.CodeChallengeMethod != "" && (GenOAuth.CodeChallengeMethod != "plain" && GenOAuth.CodeChallengeMethod != "S256"): return errors.New("configuration error: oauth.code_challenge_method must be either 'S256' or 'plain'") From 0c1ff37962759a32aa696e6f186aa76fba15d5b6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 9 Sep 2021 10:30:57 -0700 Subject: [PATCH 618/736] #417 azure shouldn't require `oauth.user_info_url` --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cc3b459..efb62cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.34.1 + +- bug fix: [Azure provider no longer requires `oauth.user_info_url` to be configured](https://github.com/vouch/vouch-proxy/issues/417) + ## v0.34.0 - add support for [the "claims" Request Parameter](https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) to support Twitch OIDC as IdP From 2163a840a78c6dc62f95df139ce05e200078d432 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 9 Sep 2021 10:45:22 -0700 Subject: [PATCH 619/736] link to local dev SPA example --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a9eccaf..0cfd9e88 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,6 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) - [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) ---- - ## What Vouch Proxy Does Vouch Proxy (VP) forces visitors to login and authenticate with an [IdP](https://en.wikipedia.org/wiki/Identity_provider) (such as one of the services listed above) before allowing them access to a website. @@ -262,6 +260,7 @@ All Vouch Proxy configuration items are documented in [config/config.yml_example - [FreeBSD support](https://github.com/vouch/vouch-proxy/issues/368) - [systemd startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) - [using Node.js instead of Nginx to route requests](https://github.com/vouch/vouch-proxy/issues/359) +- [Developing a Single Page App (SPA) while consuming a VP protected API](https://github.com/vouch/vouch-proxy/issues/416) Please do help us to expand this list. @@ -386,7 +385,7 @@ this url must be present in the configuration file on the list `vouch.post_logou # the URL must still be passed to Vouch Proxy as https://vouch.yourdomain.com/logout?url=${ONE OF THE URLS BELOW} post_logout_redirect_uris: # your apps login page - - http://.yourdomain.com/login + - https://yourdomain.com/login # your IdPs logout enpoint # from https://accounts.google.com/.well-known/openid-configuration - https://oauth2.googleapis.com/revoke From 78349de90e55df8fe57cf2e6ce86f15bdd0b2165 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 9 Sep 2021 19:07:10 -0700 Subject: [PATCH 620/736] link to `satisfy any;` example --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0cfd9e88..e1d5d50f 100644 --- a/README.md +++ b/README.md @@ -249,18 +249,19 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) -- [cacheing of the Vouch Proxy validation response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) -- [handleing `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) -- [validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) -- [running on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) +- [Cacheing of the Vouch Proxy `/validate` response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) +- [Handleing `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) +- [Validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) +- [Running VP on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) - [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) - [set `HTTP_PROXY` to relay Vouch Proxy IdP requests through an outbound proxy server](https://github.com/vouch/vouch-proxy/issues/291) - [Reverse Proxy for Google Cloud Run Services](https://github.com/karthikv2k/oauth_reverse_proxy) - [Enable native TLS in Vouch Proxy](https://github.com/vouch/vouch-proxy/pull/332#issue-522612010) - [FreeBSD support](https://github.com/vouch/vouch-proxy/issues/368) -- [systemd startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) -- [using Node.js instead of Nginx to route requests](https://github.com/vouch/vouch-proxy/issues/359) +- [`systemd` startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) +- [Using Node.js instead of Nginx to route requests](https://github.com/vouch/vouch-proxy/issues/359) - [Developing a Single Page App (SPA) while consuming a VP protected API](https://github.com/vouch/vouch-proxy/issues/416) +- [Filter by IP address before VP validation by using `satisfy any;`](https://github.com/vouch/vouch-proxy/issues/378#issuecomment-814423460) Please do help us to expand this list. From f829aa791b1c97e502cf423f7ce5532124badb9e Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 23 Sep 2021 15:10:30 +1000 Subject: [PATCH 621/736] Add proxy_ssl verify statements to the k8s-ingress example, to avoid opening up a MITM vulnerability --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index e1d5d50f..dce83a9f 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,14 @@ If you are using kubernetes with [nginx-ingress](https://github.com/kubernetes/i nginx.ingress.kubernetes.io/auth-url: https://vouch.yourdomain.com/validate nginx.ingress.kubernetes.io/auth-response-headers: X-Vouch-User nginx.ingress.kubernetes.io/auth-snippet: | + # If your Vouch is using HTTPS and is hosted externally to k8s, you + # should uncomment the following values to ensure the SSL cert is + # valid. Nginx does not validate SSL certs by default, so it could + # be a MITM risk otherwise. + # proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; + # proxy_ssl_session_reuse on; + # proxy_ssl_verify_depth 2; + # proxy_ssl_verify on; # these return values are used by the @error401 call auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt; auth_request_set $auth_resp_err $upstream_http_x_vouch_err; From 3c2031ffadb4c6bada181627032cf8b6421e62de Mon Sep 17 00:00:00 2001 From: Jonathan Boutsicaris Date: Sun, 26 Sep 2021 12:52:03 +0300 Subject: [PATCH 622/736] docs: sample vouch-proxy 'in a path' typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e1d5d50f..5e1aacb4 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ server { location @error401 { # redirect to Vouch Proxy for login - return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err + return 302 https://protectedapp.yourdomain.com/vp_in_a_path/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err; } location / { @@ -219,7 +219,7 @@ server { proxy_pass http://127.0.0.1:8080; # see the Nginx config above for additional headers which can be set from Vouch Proxy } - +} ``` ### Additional Nginx Configurations From a912d00f3065b689c824b1b1615b11ca6208e497 Mon Sep 17 00:00:00 2001 From: Zain Patel Date: Mon, 4 Oct 2021 14:51:41 +0100 Subject: [PATCH 623/736] Make session maxage configurable --- .defaults.yml | 1 + config/config.yml_example | 2 ++ handlers/handlers.go | 2 +- pkg/cfg/cfg.go | 5 +++-- pkg/cfg/cfg_test.go | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index 43b8bdf8..a730cdd9 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -38,6 +38,7 @@ vouch: session: name: VouchSession + maxAge: 300 # key: headers: diff --git a/config/config.yml_example b/config/config.yml_example index ce9cbb04..d2ed8dbc 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -121,6 +121,8 @@ vouch: session: # name of session variable stored locally - VOUCH_SESSION_NAME name: VouchSession + # number of minutes for maximum session age, configuring how long the user has to login at their IdP (defaults to 300) - VOUCH_SESSION_MAXAGE + maxAge: 300 # key - a cryptographic string used to store the session variable - VOUCH_SESSION_KEY # if the key is not set here then it is generated at startup and stored in memory # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes) diff --git a/handlers/handlers.go b/handlers/handlers.go index 4427738f..5f2f8a80 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -59,7 +59,7 @@ func Configure() { sessstore.Options.HttpOnly = cfg.Cfg.Cookie.HTTPOnly sessstore.Options.Secure = cfg.Cfg.Cookie.Secure sessstore.Options.SameSite = cookie.SameSite() - sessstore.Options.MaxAge = 300 // give the user five minutes to log in at the IdP + sessstore.Options.MaxAge = cfg.Cfg.Session.MaxAge // how long the user has to login to the IdP provider = getProvider() provider.Configure() diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index d462f207..063e0b47 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -87,8 +87,9 @@ type Config struct { ClaimsCleaned map[string]string // the rawClaim is mapped to the actual claims header } Session struct { - Name string `mapstructure:"name"` - Key string `mapstructure:"key"` + Name string `mapstructure:"name"` + MaxAge int `mapstructure:"maxage"` + Key string `mapstructure:"key"` } TestURL string `mapstructure:"test_url"` TestURLs []string `mapstructure:"test_urls"` diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index dc7ffb74..7c9479a5 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -134,7 +134,7 @@ func Test_configureFromEnvCfg(t *testing.T) { senv := []string{"VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", - "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} + "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_MAXAGE", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} // array of strings saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} // int From db0c85ca3c83d3a918fb3cd804781b10696ff2bc Mon Sep 17 00:00:00 2001 From: Zain Patel Date: Mon, 4 Oct 2021 16:11:39 +0100 Subject: [PATCH 624/736] Fix placement of test --- pkg/cfg/cfg_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 7c9479a5..caf13c25 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -134,11 +134,11 @@ func Test_configureFromEnvCfg(t *testing.T) { senv := []string{"VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", - "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_MAXAGE", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} + "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} // array of strings saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} // int - ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE"} + ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE", "VOUCH_SESSION_MAXAGE"} // bool benv := []string{"VOUCH_ALLOWALLUSERS", "VOUCH_PUBLICACCESS", "VOUCH_JWT_COMPRESS", "VOUCH_COOKIE_SECURE", "VOUCH_COOKIE_HTTPONLY", "VOUCH_TESTING"} From ba733b775b80f96213bbd4ed189c421dcf1d1edd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 Oct 2021 15:12:44 -0700 Subject: [PATCH 625/736] #433 add warning about required scopes --- pkg/cfg/oauth.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 79b033aa..56442d64 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -142,6 +142,8 @@ func oauthBasicTest() error { return errors.New("configuration error: oauth.user_info_url not found") case GenOAuth.CodeChallengeMethod != "" && (GenOAuth.CodeChallengeMethod != "plain" && GenOAuth.CodeChallengeMethod != "S256"): return errors.New("configuration error: oauth.code_challenge_method must be either 'S256' or 'plain'") + case GenOAuth.Provider == Providers.Azure || GenOAuth.Provider == Providers.ADFS || GenOAuth.Provider == Providers.Nextcloud || GenOAuth.Provider == Providers.OIDC: + checkScopes([]string{"openid", "email", "profile"}) } if GenOAuth.RedirectURL != "" { @@ -156,9 +158,20 @@ func oauthBasicTest() error { } } } + return nil } +func checkScopes(scopes []string) { + for _, s := range scopes { + if !arrContains(GenOAuth.Scopes, s) { + log.Warnf("Configuration Warning: for 'oauth.provider: %s', 'oauth.scopes' should usually contain: -%s", GenOAuth.Provider, strings.Join(scopes, " -")) + return + } + } +} + +// TODO: all of these methods should become `provider.SetDefaults()` or `provider.SetDefaults(*GenOAuth)` func setProviderDefaults() { if GenOAuth.Provider == Providers.Google { setDefaultsGoogle() @@ -289,3 +302,12 @@ func checkCallbackConfig(url string) error { return nil } + +func arrContains(arr []string, str string) bool { + for _, v := range arr { + if v == str { + return true + } + } + return false +} From 894baad75b6bffb1a0a2ee4224a1972f1ddab472 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 8 Oct 2021 09:51:23 +0200 Subject: [PATCH 626/736] Add missing `Set` and `tableHasKey` functions --- examples/OpenResty/lua/group_auth.lua | 12 +++++++++++- examples/OpenResty/lua/user_auth.lua | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/OpenResty/lua/group_auth.lua b/examples/OpenResty/lua/group_auth.lua index 83e7c619..a86da9a9 100644 --- a/examples/OpenResty/lua/group_auth.lua +++ b/examples/OpenResty/lua/group_auth.lua @@ -2,6 +2,16 @@ -- Group Authentication -- via X-Vouch-IdP-Groups -- ============================== +-- Function to turn a table with only values into a k=>v table +function Set (list) + local set = {} + for _, l in ipairs(list) do set[l] = true end + return set +end +-- Function to find a key in a table +function tableHasKey(table,key) + return table[key] ~= nil +end -- Validate that a user is in a group local authorized_groups = Set { "CN=Domain Users,CN=Users,DC=Contoso,DC=com", @@ -29,4 +39,4 @@ if ngx.var.auth_resp_x_vouch_idp_claims_groups then else -- Throw forbidden if variable doesn't exist ngx.exit(ngx.HTTP_FORBIDDEN) -end \ No newline at end of file +end diff --git a/examples/OpenResty/lua/user_auth.lua b/examples/OpenResty/lua/user_auth.lua index 91f6c62a..e979cbcc 100644 --- a/examples/OpenResty/lua/user_auth.lua +++ b/examples/OpenResty/lua/user_auth.lua @@ -2,6 +2,16 @@ -- User Authentication -- via X-Vouch-User -- ============================== +-- Function to turn a table with only values into a k=>v table +function Set (list) + local set = {} + for _, l in ipairs(list) do set[l] = true end + return set +end +-- Function to find a key in a table +function tableHasKey(table,key) + return table[key] ~= nil +end -- Validate a user in nginx, instead of vouch local authorized_users = Set { "my@account.com", @@ -17,4 +27,4 @@ if ngx.var.auth_resp_x_vouch_user then else -- Throw forbidden if variable doesn't exist ngx.exit(ngx.HTTP_FORBIDDEN) -end \ No newline at end of file +end From 50a30368d4e9262dcca7c2819dd74a70c903752a Mon Sep 17 00:00:00 2001 From: Rahul De Date: Fri, 8 Oct 2021 10:37:07 +0200 Subject: [PATCH 627/736] Set logging level private token to debug - The current logging level of this is error and we have been logging this is production for a long time --- pkg/providers/github/github.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/providers/github/github.go b/pkg/providers/github/github.go index 018806ef..8fa7e932 100644 --- a/pkg/providers/github/github.go +++ b/pkg/providers/github/github.go @@ -44,7 +44,7 @@ func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims // http.Error(w, err.Error(), http.StatusBadRequest) return err } - log.Errorf("ptoken.AccessToken: %s", ptoken.AccessToken) + log.Debugf("ptoken.AccessToken: %s", ptoken.AccessToken) userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL + ptoken.AccessToken) if err != nil { // http.Error(w, err.Error(), http.StatusBadRequest) From 46fc9fa57d49a13e4967133238307037e8b371f4 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Oct 2021 06:33:31 -0700 Subject: [PATCH 628/736] move sameSite config to cookie.Configure() --- pkg/cookie/cookie.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index 32ce35d8..b544eaf9 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -27,10 +27,12 @@ import ( const maxCookieSize = 4000 var log *zap.SugaredLogger +var sameSite http.SameSite // Configure see main.go configure() func Configure() { log = cfg.Logging.Logger + sameSite = SameSite() } // SetCookie http @@ -47,7 +49,6 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { domain = cfg.Cfg.Cookie.Domain log.Debugf("setting the cookie domain to %v", domain) } - sameSite := SameSite() cookie := http.Cookie{ Name: cfg.Cfg.Cookie.Name, From 17cf3f6cc98b685903f7bbae49afa9c4efc1756d Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Oct 2021 06:40:00 -0700 Subject: [PATCH 629/736] #428 move and edit for clarity --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dce83a9f..c99d67ea 100644 --- a/README.md +++ b/README.md @@ -341,18 +341,15 @@ If you are using kubernetes with [nginx-ingress](https://github.com/kubernetes/i nginx.ingress.kubernetes.io/auth-url: https://vouch.yourdomain.com/validate nginx.ingress.kubernetes.io/auth-response-headers: X-Vouch-User nginx.ingress.kubernetes.io/auth-snippet: | - # If your Vouch is using HTTPS and is hosted externally to k8s, you - # should uncomment the following values to ensure the SSL cert is - # valid. Nginx does not validate SSL certs by default, so it could - # be a MITM risk otherwise. - # proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; - # proxy_ssl_session_reuse on; - # proxy_ssl_verify_depth 2; - # proxy_ssl_verify on; # these return values are used by the @error401 call auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt; auth_request_set $auth_resp_err $upstream_http_x_vouch_err; auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount; + # when VP is hosted externally to k8s ensure the SSL cert is valid to avoid MITM risk + # proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; + # proxy_ssl_session_reuse on; + # proxy_ssl_verify_depth 2; + # proxy_ssl_verify on; ``` Helm Charts are maintained by [halkeye](https://github.com/halkeye) and are available at [https://github.com/halkeye-helm-charts/vouch](https://github.com/halkeye-helm-charts/vouch) / [https://halkeye.github.io/helm-charts/](https://halkeye.github.io/helm-charts/) From 7f8d0ebeee5c999cee3dc9c741ad0bc7322306da Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Oct 2021 06:50:23 -0700 Subject: [PATCH 630/736] v0.34.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index efb62cb8..4a375329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.34.2 + +- [log github token only at `logLevel: debug`](https://github.com/vouch/vouch-proxy/pull/436) +- documentation edits +- move `cookie.sameSite` configuration to `cookie.Configure()` + ## v0.34.1 - bug fix: [Azure provider no longer requires `oauth.user_info_url` to be configured](https://github.com/vouch/vouch-proxy/issues/417) From 4c364dd19dc97beac76d7859326ad27935188061 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Oct 2021 07:18:49 -0700 Subject: [PATCH 631/736] #318 configure as minutes This is consistent with the other `MaxAge` settings --- .defaults.yml | 2 +- CHANGELOG.md | 4 ++++ config/config.yml_example | 2 +- handlers/handlers.go | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index a730cdd9..d6cea00c 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -38,7 +38,7 @@ vouch: session: name: VouchSession - maxAge: 300 + maxAge: 5 # key: headers: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a375329..1685e427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.35.0 + +- [make session.MaxAge configurable](https://github.com/vouch/vouch-proxy/issues/318) to allow more time to login at the IdP + ## v0.34.2 - [log github token only at `logLevel: debug`](https://github.com/vouch/vouch-proxy/pull/436) diff --git a/config/config.yml_example b/config/config.yml_example index d2ed8dbc..afdc3f83 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -122,7 +122,7 @@ vouch: # name of session variable stored locally - VOUCH_SESSION_NAME name: VouchSession # number of minutes for maximum session age, configuring how long the user has to login at their IdP (defaults to 300) - VOUCH_SESSION_MAXAGE - maxAge: 300 + maxAge: 5 # key - a cryptographic string used to store the session variable - VOUCH_SESSION_KEY # if the key is not set here then it is generated at startup and stored in memory # Vouch Proxy complains if the string is less than 44 characters (256 bits as 32 base64 bytes) diff --git a/handlers/handlers.go b/handlers/handlers.go index 5f2f8a80..6dae94e3 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -59,7 +59,7 @@ func Configure() { sessstore.Options.HttpOnly = cfg.Cfg.Cookie.HTTPOnly sessstore.Options.Secure = cfg.Cfg.Cookie.Secure sessstore.Options.SameSite = cookie.SameSite() - sessstore.Options.MaxAge = cfg.Cfg.Session.MaxAge // how long the user has to login to the IdP + sessstore.Options.MaxAge = cfg.Cfg.Session.MaxAge * 60 // convert minutes to seconds provider = getProvider() provider.Configure() From f8410f4ab8569021c389f7a030254b516ae34980 Mon Sep 17 00:00:00 2001 From: Zain Patel Date: Fri, 8 Oct 2021 15:21:39 +0100 Subject: [PATCH 632/736] Specify default is 5 --- config/config.yml_example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yml_example b/config/config.yml_example index afdc3f83..3b37a55d 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -121,7 +121,7 @@ vouch: session: # name of session variable stored locally - VOUCH_SESSION_NAME name: VouchSession - # number of minutes for maximum session age, configuring how long the user has to login at their IdP (defaults to 300) - VOUCH_SESSION_MAXAGE + # number of minutes for maximum session age, configuring how long the user has to login at their IdP (defaults to 5) - VOUCH_SESSION_MAXAGE maxAge: 5 # key - a cryptographic string used to store the session variable - VOUCH_SESSION_KEY # if the key is not set here then it is generated at startup and stored in memory From 8e4683ba0d5e24e827f997ef23f9c011e98f1e45 Mon Sep 17 00:00:00 2001 From: Rene Date: Thu, 14 Oct 2021 19:36:24 +0200 Subject: [PATCH 633/736] fix: make renderError() regard DocumentRoot config var --- pkg/responses/responses.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 0373964b..24dd65c4 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -61,7 +61,7 @@ func renderError(w http.ResponseWriter, msg string, status int) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(status) - if err := indexTemplate.Execute(w, &Index{Msg: msg}); err != nil { + if err := indexTemplate.Execute(w, &Index{Msg: msg, DocumentRoot: cfg.Cfg.DocumentRoot}); err != nil { log.Error(err) } } @@ -74,7 +74,7 @@ func OK200(w http.ResponseWriter, r *http.Request) { } } -// Redirect302 redirect to the specificed rURL +// Redirect302 redirect to the specified rURL func Redirect302(w http.ResponseWriter, r *http.Request, rURL string) { if cfg.Cfg.Testing { cfg.Cfg.TestURLs = append(cfg.Cfg.TestURLs, rURL) From da481b8b9ab4336a238ba12cc37612ee4064e586 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 15 Oct 2021 17:49:19 -0700 Subject: [PATCH 634/736] fix #441 https callback_urls --- config/config.yml_example_google | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/config.yml_example_google b/config/config.yml_example_google index 9dd3dd81..7b9726c0 100644 --- a/config/config.yml_example_google +++ b/config/config.yml_example_google @@ -23,8 +23,9 @@ oauth: # https://console.developers.google.com/apis/credentials client_id: xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + # Google may require callbac_urls (redirect URIs) to be 'https' callback_urls: - - http://yourdomain.com:9090/auth - - http://yourotherdomain.com:9090/auth + - https://yourdomain.com:9090/auth + - https://yourotherdomain.com:9090/auth preferredDomain: yourdomain.com # be careful with this option, it may conflict with chrome on Android # endpoints are set from https://godoc.org/golang.org/x/oauth2/google From 0eaaeae675243f8318b1e8a91282cdb45e9bb895 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 15 Oct 2021 18:12:45 -0700 Subject: [PATCH 635/736] #421 link to issue from README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5e1aacb4..e714f0c2 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ All Vouch Proxy configuration items are documented in [config/config.yml_example - [`systemd` startup of Vouch Proxy](https://github.com/vouch/vouch-proxy/tree/master/examples/startup) - [Using Node.js instead of Nginx to route requests](https://github.com/vouch/vouch-proxy/issues/359) - [Developing a Single Page App (SPA) while consuming a VP protected API](https://github.com/vouch/vouch-proxy/issues/416) +- [Integrate Vouch Proxy into a server side application for User Authn and Authz](https://github.com/vouch/vouch-proxy/issues/421) - [Filter by IP address before VP validation by using `satisfy any;`](https://github.com/vouch/vouch-proxy/issues/378#issuecomment-814423460) Please do help us to expand this list. From b2667053e4c150fbe438bd69f9c64208e8279581 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 15 Oct 2021 18:24:51 -0700 Subject: [PATCH 636/736] #439 honor DocumentRoot for error pages --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1685e427..3ffaef3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.35.1 + +- [include DocumentRoot if configured in error pages](https://github.com/vouch/vouch-proxy/pull/439) + ## v0.35.0 - [make session.MaxAge configurable](https://github.com/vouch/vouch-proxy/issues/318) to allow more time to login at the IdP From 6a498ab18dd6dbaff674a2daf63d814070d4ab42 Mon Sep 17 00:00:00 2001 From: Adam Panzer Date: Tue, 2 Nov 2021 17:07:38 -0700 Subject: [PATCH 637/736] run as non-root --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 16901da9..1cb843b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,12 @@ FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /go/bin/vouch-proxy /vouch-proxy + +RUN groupadd -g 1001 vouch && \ + useradd -m vouch_user --uid=1001 --gid=1001 && \ + chown vouch_user:vouch /etc/ssl/certs/ca-certificates.crt && \ + chown vouch_user:vouch /vouch-proxy + EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] HEALTHCHECK --interval=1m --timeout=5s CMD [ "/vouch-proxy", "-healthcheck" ] From 59c7433c1373e6fc7cf307c25ca6f0fe3963bad7 Mon Sep 17 00:00:00 2001 From: Adam Panzer Date: Tue, 2 Nov 2021 17:10:45 -0700 Subject: [PATCH 638/736] do.sh --- Dockerfile.alpine | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9e668b0f..45f5e09b 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -23,6 +23,13 @@ RUN apk add --no-cache bash COPY do.sh /do.sh COPY --from=builder /go/bin/vouch-proxy /vouch-proxy + +RUN groupadd -g 1001 vouch && \ + useradd -m vouch_user --uid=1001 --gid=1001 && \ + chown vouch_user:vouch /etc/ssl/certs/ca-certificates.crt && \ + chown vouch_user:vouch /vouch-proxy && \ + chown vouch_user:vouch /do.sh + EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] HEALTHCHECK --interval=1m --timeout=5s CMD [ "/vouch-proxy", "-healthcheck" ] From 51b5bfe7242bc1cc2233c421170fbbeb9d136e44 Mon Sep 17 00:00:00 2001 From: Adam Panzer Date: Tue, 2 Nov 2021 17:27:40 -0700 Subject: [PATCH 639/736] successful build --- Dockerfile | 8 ++++---- Dockerfile.alpine | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1cb843b3..9e573009 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,8 @@ COPY . . # RUN go-wrapper download # "go get -d -v ./..." # RUN ./do.sh build # see `do.sh` for vouch build details # RUN go-wrapper install # "go install -v ./..." +RUN groupadd -g 1001 vouch && \ + useradd -m vouch_user --uid=1001 --gid=1001 RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details @@ -20,12 +22,10 @@ RUN ./do.sh install FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=builder /etc/passwd /etc/passwd COPY --from=builder /go/bin/vouch-proxy /vouch-proxy -RUN groupadd -g 1001 vouch && \ - useradd -m vouch_user --uid=1001 --gid=1001 && \ - chown vouch_user:vouch /etc/ssl/certs/ca-certificates.crt && \ - chown vouch_user:vouch /vouch-proxy +USER vouch_user EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 45f5e09b..465ff6dd 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -12,6 +12,8 @@ COPY . . RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details RUN ./do.sh install +RUN groupadd -g 1001 vouch && \ + useradd -m vouch_user --uid=1001 --gid=1001 FROM alpine:latest LABEL maintainer="vouch@bnf.net" @@ -23,12 +25,9 @@ RUN apk add --no-cache bash COPY do.sh /do.sh COPY --from=builder /go/bin/vouch-proxy /vouch-proxy +COPY --from=builder /etc/passwd /etc/passwd -RUN groupadd -g 1001 vouch && \ - useradd -m vouch_user --uid=1001 --gid=1001 && \ - chown vouch_user:vouch /etc/ssl/certs/ca-certificates.crt && \ - chown vouch_user:vouch /vouch-proxy && \ - chown vouch_user:vouch /do.sh +USER vouch_user EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] From f1f221f2173146f572a61f9337ec49d47b62ab60 Mon Sep 17 00:00:00 2001 From: Adam Panzer Date: Wed, 3 Nov 2021 10:24:36 -0700 Subject: [PATCH 640/736] PR Feedback --- CHANGELOG.md | 2 ++ Dockerfile.alpine | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ffaef3b..9fbf4843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +- [run vouch-proxy as non-root user](https://github.com/vouch/vouch-proxy/pull/444) + ## v0.35.1 - [include DocumentRoot if configured in error pages](https://github.com/vouch/vouch-proxy/pull/439) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 465ff6dd..bd9eca55 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -12,8 +12,11 @@ COPY . . RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details RUN ./do.sh install -RUN groupadd -g 1001 vouch && \ - useradd -m vouch_user --uid=1001 --gid=1001 + +ARG UID=1001 +ARG GID=1001 +RUN groupadd -g $GID vouch && \ + useradd -m vouch_user --uid=$UID --gid=$GID FROM alpine:latest LABEL maintainer="vouch@bnf.net" From 6a9fbd88973df76dca7185d2b2362c19e4d9c785 Mon Sep 17 00:00:00 2001 From: Adam Panzer Date: Thu, 4 Nov 2021 10:00:44 -0700 Subject: [PATCH 641/736] Add to dockerfile too! --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9e573009..64133c9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,10 @@ COPY . . # RUN go-wrapper download # "go get -d -v ./..." # RUN ./do.sh build # see `do.sh` for vouch build details # RUN go-wrapper install # "go install -v ./..." -RUN groupadd -g 1001 vouch && \ - useradd -m vouch_user --uid=1001 --gid=1001 +ARG UID=1001 +ARG GID=1001 +RUN groupadd -g $GID vouch && \ + useradd -m vouch_user --uid=$UID --gid=$GID RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details From 094d4bf05fd0c076605bef08891d5083d1683aec Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 6 Dec 2021 07:45:52 -0800 Subject: [PATCH 642/736] #288 Ory Hydra support --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8d0d3763..e3506a98 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) - [HomeAssistant](https://developers.home-assistant.io/docs/en/auth_api.html) - [OpenStax](https://github.com/vouch/vouch-proxy/pull/141) +- [Ory Hydra](https://github.com/vouch/vouch-proxy/issues/288) - [Nextcloud](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/oauth2.html) - most other OpenID Connect (OIDC) providers From 72fcdad78593000dec81e064247794f4fc474f78 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 6 Dec 2021 15:54:47 -0800 Subject: [PATCH 643/736] use 'quay.io/vouch/vouch-proxy' image names --- do.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/do.sh b/do.sh index 8fbdbb5b..d5da8aa2 100755 --- a/do.sh +++ b/do.sh @@ -11,8 +11,8 @@ if [ -z "$VOUCH_ROOT" ]; then export VOUCH_ROOT=${GOPATH}/src/github.com/vouch/vouch-proxy/ fi -IMAGE=voucher/vouch-proxy:latest -ALPINE=voucher/vouch-proxy:alpine +IMAGE=quay.io/vouch/vouch-proxy:latest +ALPINE=quay.io/vouch/vouch-proxy:alpine-latest GOIMAGE=golang:1.16 NAME=vouch-proxy HTTPPORT=9090 @@ -394,7 +394,7 @@ usage() { $0 bug_report domain.com [badstr2..] - print config file and log removing secrets and each provided string $0 gogo [gocmd] - run, build, any go cmd $0 stats - simple metrics (lines of code in project, number of go files) - $0 watch [cmd] - watch the $CWD for any change and re-reun the [cmd] + $0 watch [cmd] - watch the \$CWD for any change and re-reun the [cmd] (defaults to 'go run main.go') $0 license [file] - apply the license to the file do is like make From 07d1482d7d6e63fb8bd2331022c21ebdc4646ef9 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Mon, 6 Dec 2021 16:06:51 -0800 Subject: [PATCH 644/736] #442 in Docker containers run as user `vouch` --- CHANGELOG.md | 6 +++++- Dockerfile | 17 ++++++++--------- Dockerfile.alpine | 15 ++++++++------- README.md | 2 ++ pkg/cfg/cfg.go | 45 ++++++++++++++++++++++++++++++++++++++++++++- pkg/cfg/jwt.go | 3 ++- 6 files changed, 69 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fbf4843..625b58bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. -- [run vouch-proxy as non-root user](https://github.com/vouch/vouch-proxy/pull/444) +## v0.36.0 + +- [run Docker containers as non-root user](https://github.com/vouch/vouch-proxy/pull/444) + +Permissions may need to be adjusted for `/config/secret` and `/config/config.yml` in Docker environemnts. See the [README](https://github.com/vouch/vouch-proxy#running-from-docker) ## v0.35.1 diff --git a/Dockerfile b/Dockerfile index 64133c9f..6639badd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,19 @@ -# voucher/vouch-proxy +# quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy FROM golang:1.16 AS builder +ARG UID=999 +ARG GID=999 LABEL maintainer="vouch@bnf.net" RUN mkdir -p ${GOPATH}/src/github.com/vouch/vouch-proxy WORKDIR ${GOPATH}/src/github.com/vouch/vouch-proxy +RUN groupadd -g $GID vouch \ + && useradd --system vouch --uid=$UID --gid=$GID + COPY . . -# RUN go-wrapper download # "go get -d -v ./..." -# RUN ./do.sh build # see `do.sh` for vouch build details -# RUN go-wrapper install # "go install -v ./..." -ARG UID=1001 -ARG GID=1001 -RUN groupadd -g $GID vouch && \ - useradd -m vouch_user --uid=$UID --gid=$GID RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details @@ -25,9 +23,10 @@ FROM scratch LABEL maintainer="vouch@bnf.net" COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /etc/group /etc/group COPY --from=builder /go/bin/vouch-proxy /vouch-proxy -USER vouch_user +USER vouch EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index bd9eca55..2f155625 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,7 +1,9 @@ -# voucher/vouch-proxy +# quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy FROM golang:1.16 AS builder +ARG UID=999 +ARG GID=999 LABEL maintainer="vouch@bnf.net" RUN mkdir -p ${GOPATH}/src/github.com/vouch/vouch-proxy @@ -13,10 +15,8 @@ RUN ./do.sh goget RUN ./do.sh gobuildstatic # see `do.sh` for vouch-proxy build details RUN ./do.sh install -ARG UID=1001 -ARG GID=1001 -RUN groupadd -g $GID vouch && \ - useradd -m vouch_user --uid=$UID --gid=$GID +RUN groupadd -g $GID vouch \ + && useradd --system vouch --uid=$UID --gid=$GID FROM alpine:latest LABEL maintainer="vouch@bnf.net" @@ -27,10 +27,11 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certifi RUN apk add --no-cache bash COPY do.sh /do.sh -COPY --from=builder /go/bin/vouch-proxy /vouch-proxy COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /etc/group /etc/group +COPY --from=builder /go/bin/vouch-proxy /vouch-proxy -USER vouch_user +USER vouch EXPOSE 9090 ENTRYPOINT ["/vouch-proxy"] diff --git a/README.md b/README.md index e3506a98..deb6ab4a 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,8 @@ docker run -d \ quay.io/vouch/vouch-proxy ``` +As of `v0.36.0` the docker process in the container runs as user `vouch` with UID 999 and GID 999. You may need to set the permissions of `/config/config.yml` and `/config/secret` to correspond to be readable by this user, or otherwise use `docker run --user $UID:$GID ...` or perhaps build the docker container from source and use the available ARGs for UID and GID. + Automated container builds for each Vouch Proxy release are available from [quay.io](https://quay.io/repository/vouch/vouch-proxy). Each release produces.. a minimal go binary container built from `Dockerfile` diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 063e0b47..14629879 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -20,6 +20,7 @@ import ( "io/ioutil" "net/http" "os" + "os/user" "path" "path/filepath" "reflect" @@ -193,6 +194,7 @@ func Configure() { if !didConfigFromEnv && configFileErr != nil { // then it's probably config file not found + logSysInfo() log.Fatal(configFileErr) } @@ -207,7 +209,6 @@ func Configure() { if *CmdLine.port != -1 { Cfg.Port = *CmdLine.port } - logConfigIfDebug() } @@ -285,6 +286,7 @@ func parseConfigFile() error { } err := viper.ReadInConfig() // Find and read the config file if err != nil { // Handle errors reading the config file + return fmt.Errorf("%w: %s", errConfigNotFound, err) } @@ -677,3 +679,44 @@ func SigningKey() (interface{}, error) { return key, nil } + +// Check that we have read permission for this file +// https://stackoverflow.com/questions/60128401/how-to-check-if-a-file-is-executable-in-go +func canRead(file string) bool { + stat, err := os.Stat(file) + if err != nil { + log.Debug(err) + return false + } + + m := stat.Mode() + return m&0400 != 0 +} + +// detect if we're in a docker environment +func isDocker() bool { + return canRead("/.dockerenv") +} + +func logSysInfo() { + if isDocker() { + log.Warn("detected Docker environment, beware of Docker userid and permissions changes in v0.36.0") + } + u, err := user.Current() + if err != nil { + log.Error(err) + } + g, err := user.LookupGroupId(u.Gid) + if err != nil { + log.Error(err) + } + p, err := os.FindProcess(os.Getpid()) + if err != nil { + log.Error(err) + } + exe, err := os.Executable() + if err != nil { + log.Error(err) + } + log.Debugf("%s was executed as '%s' (pid: %d) running as user %s (uid: %s) with group %s (gid: %s)", Branding.FullName, exe, p.Pid, u.Username, u.Uid, g.Name, u.Gid) +} diff --git a/pkg/cfg/jwt.go b/pkg/cfg/jwt.go index 080d99ce..bead1961 100644 --- a/pkg/cfg/jwt.go +++ b/pkg/cfg/jwt.go @@ -35,7 +35,8 @@ func getOrGenerateJWTSecret() string { b = []byte(rstr) err = ioutil.WriteFile(secretFile, b, 0600) if err != nil { - log.Debug(err) + log.Error(err) + logSysInfo() } } return string(b) From 2eee0d52c3d8a025355d3c4df18f811a60b62d16 Mon Sep 17 00:00:00 2001 From: Massimo Cetra Date: Tue, 4 Jan 2022 00:07:39 +0100 Subject: [PATCH 645/736] Adding the example for a Gitlab CE configuration example --- config/config.yml_example_gitlab_ce | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 config/config.yml_example_gitlab_ce diff --git a/config/config.yml_example_gitlab_ce b/config/config.yml_example_gitlab_ce new file mode 100644 index 00000000..70cf8a1c --- /dev/null +++ b/config/config.yml_example_gitlab_ce @@ -0,0 +1,35 @@ +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with GitLab CE Authentication + +vouch: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + - yourdomain.com + - yourotherdomain.com + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + # Create a new global or group application and paste the id and the secret + provider: oidc + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + scopes: + - openid + - email + - profile + auth_url: https://gitlab.yourdomain.com/oauth/authorize + token_url: https://gitlab.yourdomain.com/oauth/token + user_info_url: https://gitlab.yourdomain.com/oauth/userinfo + callback_url: http://vouch.yourdomain.com:9090/auth From 3527b3de64d9105ba8aba8e330f9e04649bf422f Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Fri, 25 Feb 2022 13:32:22 +0000 Subject: [PATCH 646/736] Remove contributing details into a file.. ..so that it can be referenced in the helm-charts repo. --- CONTRIBUTING.md | 18 ++++++++++++++++++ README.md | 19 ++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ee3b160c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +### Contributing to Vouch Proxy by submitting a Pull Request + +**_I really love Vouch Proxy! I wish it did XXXX..._** + +That's really wonderful and contributions are greatly appreciated. However, please search through the existing issues, both open and closed, to look for any prior work or conversation. Then please make a proposal before we all spend valuable time considering and integrating a new feature. + +Code contributions should.. + +- generally be discussed beforehand in a GitHub issue +- include unit tests and in some cases end-to-end tests +- be formatted with `go fmt`, checked with `go vet` and other common go tools +- accomodate configuration via `config.yml` as well as `ENVIRONMENT_VARIABLEs`. +- not break existing setups without a clear reason (usually security related) +- include an entry at the top of CHANGELOG.md in the **Unreleased** section + +For larger contributions or code related to a platform that we don't currently support we will ask you to commit to supporting the feature for an agreed upon period. Invariably someone will pop up here with a question and we want to be able to support these requests. + +**Thank you to all of the contributors that have provided their time and effort and thought to improving VP.** diff --git a/README.md b/README.md index deb6ab4a..3949c7c5 100644 --- a/README.md +++ b/README.md @@ -475,24 +475,9 @@ A bug report can be generated from a docker environment using the `quay.io/vouch docker run --name vouch_proxy -v $PWD/config:/config -v $PWD/certs:/certs -it --rm --entrypoint /do.sh quay.io/vouch/vouch-proxy:alpine bug_report yourdomain.com anotherdomain.com someothersecret ``` -### Contributing to Vouch Proxy by submitting a Pull Request +### Contributing -**_I really love Vouch Proxy! I wish it did XXXX..._** - -That's really wonderful and contributions are greatly appreciated. However, please search through the existing issues, both open and closed, to look for any prior work or conversation. Then please make a proposal before we all spend valuable time considering and integrating a new feature. - -Code contributions should.. - -- generally be discussed beforehand in a GitHub issue -- include unit tests and in some cases end-to-end tests -- be formatted with `go fmt`, checked with `go vet` and other common go tools -- accomodate configuration via `config.yml` as well as `ENVIRONMENT_VARIABLEs`. -- not break existing setups without a clear reason (usually security related) -- include an entry at the top of CHANGELOG.md in the **Unreleased** section - -For larger contributions or code related to a platform that we don't currently support we will ask you to commit to supporting the feature for an agreed upon period. Invariably someone will pop up here with a question and we want to be able to support these requests. - -**Thank you to all of the contributors that have provided their time and effort and thought to improving VP.** +We'd love to have you contribute! Please refer to our [contribution guidelines](https://github.com/vouch/vouch-proxy/blob/master/CONTRIBUTING.md) for details. ## Advanced Authorization Using OpenResty From 6c3da04aac0d651553371671a3b9d69720908beb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 25 Feb 2022 11:53:24 -0800 Subject: [PATCH 647/736] #463 adjust TOC target link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3949c7c5..d08cb451 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim (Read this before submitting an issue at GitHub) - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) - - [submitting a Pull Request for a new feature](#submitting-a-pull-request-for-a-new-feature) + - [Contributing to Vouch Proxy](#contributing) - [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) - [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) From 4bc042c08b80fdd22573c7b0a29730224caab954 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 25 Feb 2022 12:07:16 -0800 Subject: [PATCH 648/736] #457 adjust README links and attributions for helm-charts --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d08cb451..1ef4e44f 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ If you are using kubernetes with [nginx-ingress](https://github.com/kubernetes/i # proxy_ssl_verify on; ``` -Helm Charts are maintained by [halkeye](https://github.com/halkeye) and are available at [https://github.com/halkeye-helm-charts/vouch](https://github.com/halkeye-helm-charts/vouch) / [https://halkeye.github.io/helm-charts/](https://halkeye.github.io/helm-charts/) +Helm Charts are maintained by [punkle](https://github.com/punkle), [martina-if](https://github.com/martina-if) and [halkeye](https://github.com/halkeye) and are available at [https://github.com/vouch/helm-charts](https://github.com/vouch/helm-charts) ## Compiling from source and running the binary From e656d4e298e8451cb0c5a1470fc5b5a8614707be Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 8 Mar 2022 11:11:44 -0800 Subject: [PATCH 649/736] adjust links to README --- .../open-a-github-issue-to-receive-support.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/open-a-github-issue-to-receive-support.md b/.github/ISSUE_TEMPLATE/open-a-github-issue-to-receive-support.md index 2459d947..022e2e01 100644 --- a/.github/ISSUE_TEMPLATE/open-a-github-issue-to-receive-support.md +++ b/.github/ISSUE_TEMPLATE/open-a-github-issue-to-receive-support.md @@ -8,13 +8,14 @@ assignees: '' --- **First read the README** -Specifically ***[Troubleshooting, Support and Feature Requests](https://github.com/vouch/vouch-proxy#troubleshooting-support-and-feature-requests)***. +Specifically ***[Troubleshooting, Support and Feature Requests](https://github.com/vouch/vouch-proxy#troubleshooting-support-and-feature-requests-read-this-before-submitting-an-issue-at-github)***. -And turn on `vouch.testing` before you ask for support. +And please turn on `vouch.testing` before you ask for support. -**Use a Paste Service** -We like [hasteb.in](https://hasteb.in/), but a [gist](https://gist.github.com/) is also acceptable -Do not post logs and configs to this issue + + +** Please DO NOT post config and logs to this issue, use a Gist** +We prefer a [gist](https://gist.github.com/) but any reasonable paste service is fine. **Describe the problem** A clear and concise description of the behavior you are observing. From 530f7002768c0c959c26cfa2fb2991451e717a46 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 22 Mar 2022 09:20:19 +0100 Subject: [PATCH 650/736] Fix nginx syntax highlight in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1ef4e44f..02f10270 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ The following Nginx config assumes.. - Nginx, `vouch.yourdomain.com` and `protectedapp.yourdomain.com` are running on the same server - both domains are served as `https` and have valid certs (if not, change to `listen 80` and set [vouch.cookie.secure](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L84-L85) to `false`) -```{.nginxconf} +```nginx server { listen 443 ssl http2; server_name protectedapp.yourdomain.com; @@ -164,7 +164,7 @@ server { If Vouch is configured behind the **same** nginx reverseproxy ([perhaps so you can configure ssl](https://github.com/vouch/vouch-proxy/issues/64#issuecomment-461085139)) be sure to pass the `Host` header properly, otherwise the JWT cookie cannot be set into the domain -```{.nginxconf} +```nginx server { listen 443 ssl http2; server_name vouch.yourdomain.com; @@ -185,7 +185,7 @@ As of `v0.33.0` Vouch Proxy can be served within an Nginx location (path) by con This avoids the need to setup a separate domain for Vouch Proxy such as `vouch.yourdomain.com`. For example VP login will be served from `https://protectedapp.yourdomain.com/vp_in_a_path/login` -```{.nginxconf} +```nginx server { listen 443 ssl http2; server_name protectedapp.yourdomain.com; From 044ac2a3e08d608931df0f66e23953071739a768 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Wed, 30 Mar 2022 11:01:06 +1100 Subject: [PATCH 651/736] Make WriteTimeout, ReadTimeout and IdleTimeout configurable (defaults to 15) --- .defaults.yml | 3 +++ CHANGELOG.md | 2 ++ config/config.yml_example | 11 +++++++++++ main.go | 5 +++-- pkg/cfg/cfg.go | 3 +++ pkg/cfg/cfg_test.go | 5 +++-- 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index d6cea00c..c482ebcd 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -15,6 +15,9 @@ vouch: publicAccess: false # whiteList: # teamWhitelist: + writeTimeout: 15 + readTimeout: 15 + idleTimeout: 15 tls: # cert: diff --git a/CHANGELOG.md b/CHANGELOG.md index 625b58bc..f4f61fdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +- [allow configurable Write, Read and Idle timeouts for the http server](https://github.com/vouch/vouch-proxy/pull/468) + ## v0.36.0 - [run Docker containers as non-root user](https://github.com/vouch/vouch-proxy/pull/444) diff --git a/config/config.yml_example b/config/config.yml_example index 3b37a55d..7586f5f4 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -20,6 +20,17 @@ vouch: listen: 0.0.0.0 # VOUCH_LISTEN port: 9090 # VOUCH_PORT + # The default read, write and idle timeouts are 15 seconds. + # If you have a load balancer or proxy in front that has its + # own idle timeout, you may need to ensure that the Vouch idle + # timeout is longer than the proxy's, to avoid intermittent + # 502 errors. + # See https://github.com/vouch/vouch-proxy/issues/317 for more + # information. + writeTimeout: 15 # VOUCH_WRITETIMEOUT + readTimeout: 15 # VOUCH_READTIMEOUT + idleTimeout: 15 # VOUCH_IDLETIMEOUT + # document_root - VOUCH_DOCUMENT_ROOT # see README for `Vouch Proxy "in a path"` - https://github.com/vouch/vouch-proxy#vouch-proxy-in-a-path # document_root: vp_in_a_path diff --git a/main.go b/main.go index d5e481f9..7281a910 100644 --- a/main.go +++ b/main.go @@ -196,8 +196,9 @@ func main() { Handler: router, Addr: listen, // Good practice: enforce timeouts for servers you create! - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, + WriteTimeout: time.Duration(cfg.Cfg.WriteTimeout) * time.Second, + ReadTimeout: time.Duration(cfg.Cfg.ReadTimeout) * time.Second, + IdleTimeout: time.Duration(cfg.Cfg.IdleTimeout) * time.Second, ErrorLog: log.New(&fwdToZapWriter{fastlog}, "", 0), } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 14629879..0cf82cd1 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -46,6 +46,9 @@ type Config struct { Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` DocumentRoot string `mapstructure:"document_root" envconfig:"document_root"` + WriteTimeout int `mapstructure:"writeTimeout"` + ReadTimeout int `mapstructure:"readTimeout"` + IdleTimeout int `mapstructure:"idleTimeout"` Domains []string `mapstructure:"domains"` WhiteList []string `mapstructure:"whitelist"` TeamWhiteList []string `mapstructure:"teamWhitelist"` diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index caf13c25..712bf1ca 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -138,7 +138,8 @@ func Test_configureFromEnvCfg(t *testing.T) { // array of strings saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} // int - ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE", "VOUCH_SESSION_MAXAGE"} + ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE", "VOUCH_SESSION_MAXAGE", "VOUCH_WRITETIMEOUT", "VOUCH_READTIMEOUT", + "VOUCH_IDLETIMEOUT"} // bool benv := []string{"VOUCH_ALLOWALLUSERS", "VOUCH_PUBLICACCESS", "VOUCH_JWT_COMPRESS", "VOUCH_COOKIE_SECURE", "VOUCH_COOKIE_HTTPONLY", "VOUCH_TESTING"} @@ -175,7 +176,7 @@ func Test_configureFromEnvCfg(t *testing.T) { } sacfg := [][]string{Cfg.Domains, Cfg.WhiteList, Cfg.TeamWhiteList, Cfg.Headers.Claims, Cfg.TestURLs, Cfg.LogoutRedirectURLs} - icfg := []int{Cfg.Port, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge} + icfg := []int{Cfg.Port, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge, Cfg.WriteTimeout, Cfg.ReadTimeout, Cfg.IdleTimeout} bcfg := []bool{Cfg.AllowAllUsers, Cfg.PublicAccess, Cfg.JWT.Compress, Cfg.Cookie.Secure, Cfg.Cookie.HTTPOnly, From 3ed1de335cb048e645d2ff996b40b1ab10276cb9 Mon Sep 17 00:00:00 2001 From: Samyak Sarnayak Date: Thu, 7 Apr 2022 23:23:06 +0530 Subject: [PATCH 652/736] Fix comments in Google example config The comment for `allowAllUsers` said `authenticate at Gitea`. Change it to say `authenticate with Google` (`with` seemed more appropriate than `at` here). The comment for `callback_urls` said `callbac_urls`. I suppose that was a typo. --- config/config.yml_example_google | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yml_example_google b/config/config.yml_example_google index 7b9726c0..4afaa5d9 100644 --- a/config/config.yml_example_google +++ b/config/config.yml_example_google @@ -7,7 +7,7 @@ vouch: - yourdomain.com - yourotherdomain.com - # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at Gitea + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate with Google # allowAllUsers: true cookie: @@ -23,7 +23,7 @@ oauth: # https://console.developers.google.com/apis/credentials client_id: xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com client_secret: xxxxxxxxxxxxxxxxxxxxxxxx - # Google may require callbac_urls (redirect URIs) to be 'https' + # Google may require callback_urls (redirect URIs) to be 'https' callback_urls: - https://yourdomain.com:9090/auth - https://yourotherdomain.com:9090/auth From a403478d2d8e96dda2dddd4decd984cf4d5c4225 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Apr 2022 16:39:53 -0700 Subject: [PATCH 653/736] ignore git github and whitesource --- .dockerignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.dockerignore b/.dockerignore index b06a2ee6..73c37b32 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,3 +13,6 @@ Dockerfile handlers/rice-box.go certs .cover/* +.git +.github +.whitesource From 2d3ea1243156e28e54a81da29eb3c326e9c9ce28 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 Apr 2022 16:59:30 -0700 Subject: [PATCH 654/736] v0.37.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4f61fdc..629c72fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.37.0 + - [allow configurable Write, Read and Idle timeouts for the http server](https://github.com/vouch/vouch-proxy/pull/468) ## v0.36.0 From f091f9b7da7e2bed3080a4c9d2dd80143f632c6b Mon Sep 17 00:00:00 2001 From: Jason Ribeiro Date: Thu, 9 Jun 2022 10:29:22 -0400 Subject: [PATCH 655/736] Mention github callback_url should be set to /auth --- config/config.yml_example_github | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.yml_example_github b/config/config.yml_example_github index 281c9095..ccb2dfc9 100644 --- a/config/config.yml_example_github +++ b/config/config.yml_example_github @@ -36,6 +36,9 @@ vouch: oauth: # create a new OAuth application at: # https://github.com/settings/applications/new + # + # callback_url is configured at github.com when setting up the app + # Set to e.g. https://vouch.yourdomain.com/auth provider: github client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx From 877ee115c0d6a9b749c5dc562781b3522c533dfb Mon Sep 17 00:00:00 2001 From: Jason Ribeiro Date: Fri, 10 Jun 2022 06:58:11 -0400 Subject: [PATCH 656/736] Mention vp_in_a_path for github callback_url --- config/config.yml_example_github | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yml_example_github b/config/config.yml_example_github index ccb2dfc9..25c4a68b 100644 --- a/config/config.yml_example_github +++ b/config/config.yml_example_github @@ -38,7 +38,7 @@ oauth: # https://github.com/settings/applications/new # # callback_url is configured at github.com when setting up the app - # Set to e.g. https://vouch.yourdomain.com/auth + # Set to e.g. https://vouch.yourdomain.com/auth or https://yourdomain.com/vp_in_a_path/auth provider: github client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx From 2a551a7608aa1a0f2ca660dfc73b8ea9014a230e Mon Sep 17 00:00:00 2001 From: Brian Bennett Date: Tue, 14 Jun 2022 15:41:34 -0700 Subject: [PATCH 657/736] vouch-proxy#477 Build-time hostname detection fails on platforms other than Linux and FreeBSD --- do.sh | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/do.sh b/do.sh index d5da8aa2..cced1400 100755 --- a/do.sh +++ b/do.sh @@ -25,28 +25,24 @@ run () { build () { local VERSION=$(git describe --always --long) local DT=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # ISO-8601 - local FQDN=$(_hostname) + local UQDN=$(_hostname) local SEMVER=$(git tag --list --sort="v:refname" | tail -n -1) local BRANCH=$(git rev-parse --abbrev-ref HEAD) local UNAME=$(uname) - go build -v -ldflags=" -X main.version=${VERSION} -X main.uname=${UNAME} -X main.builddt=${DT} -X main.host=${FQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . + go build -v -ldflags=" -X main.version=${VERSION} -X main.uname=${UNAME} -X main.builddt=${DT} -X main.host=${UQDN} -X main.semver=${SEMVER} -X main.branch=${BRANCH}" . } _hostname() { local FQDN - local HOSTNAME_CMD + local UQDN + FQDN=$(hostname) + UQDN=${FQDN/.*/} - case $(uname) in - FreeBSD) HOSTNAME_CMD="hostname";; - *) HOSTNAME_CMD="hostname --fqdn" - esac - - FQDN=$($HOSTNAME_CMD) - if [ -z "$FQDN" ]; then - >&2 echo "error: Could determine the fully qualified domain name using command $HOSTNAME_CMD" + if [ -z "$UQDN" ]; then + >&2 echo "error: Could determine the fully qualified domain name." return 1 fi - echo $FQDN + echo "$UQDN" return 0; } @@ -62,7 +58,7 @@ dbuild () { docker build -f Dockerfile -t $IMAGE . } -dbuildalpine () { +dbuildalpine () { docker build -f Dockerfile.alpine -t $ALPINE . } @@ -83,10 +79,10 @@ drun () { fi - CMD="docker run --rm -i -t - -p ${HTTPPORT}:${HTTPPORT} - --name $NAME - -v ${SDIR}/config:/config + CMD="docker run --rm -i -t + -p ${HTTPPORT}:${HTTPPORT} + --name $NAME + -v ${SDIR}/config:/config $WITHCERTS $IMAGE $* " @@ -126,7 +122,7 @@ bug_report() { CONFIG=config/config.yml REDACT=$* - if [ -z "$REDACT" ]; then + if [ -z "$REDACT" ]; then cat < Date: Fri, 1 Jul 2022 21:00:51 +0000 Subject: [PATCH 658/736] golang1.18 - fix parsing of invalid query strings in normalizeLoginURLParam --- go.mod | 24 +-- go.sum | 423 +++++++++++++++++++++++++++++++++++++--------- handlers/login.go | 9 +- 3 files changed, 361 insertions(+), 95 deletions(-) diff --git a/go.mod b/go.mod index 0fdb0c36..b9b31f8b 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,31 @@ module github.com/vouch/vouch-proxy go 1.16 require ( - cloud.google.com/go v0.89.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.8 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 github.com/mailru/easyjson v0.7.7 // indirect - github.com/mitchellh/mapstructure v1.4.1 - github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da + github.com/mitchellh/mapstructure v1.5.0 + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/spf13/cast v1.4.0 // indirect - github.com/spf13/viper v1.8.1 + github.com/pelletier/go-toml/v2 v2.0.2 // indirect + github.com/spf13/viper v1.12.0 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.2 + github.com/subosito/gotenv v1.4.0 // indirect github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.18.1 - golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 - golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 + golang.org/x/net v0.0.0-20220630215102-69896b714898 + golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 + golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect + gopkg.in/ini.v1 v1.66.6 // indirect ) diff --git a/go.sum b/go.sum index 4f8290c5..5ef3f2c1 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,23 +16,38 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.89.0 h1:ZT4GU+y59fC95Mfdn2RtxuzN2gc69dzlVevQK8Ykyqs= -cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -41,35 +57,59 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -77,15 +117,29 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -93,6 +147,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -134,8 +189,10 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -150,6 +207,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -157,47 +215,66 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= @@ -206,88 +283,140 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= +github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.0 h1:WhlbjwB9EGCc8W5Rxdkus+wmH2ASRwwTJk6tgHKwdqQ= -github.com/spf13/cast v1.4.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= +github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -299,21 +428,24 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -339,7 +471,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -354,8 +485,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -363,9 +493,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -384,13 +516,24 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw= +golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -402,10 +545,18 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= +golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -417,23 +568,34 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -444,6 +606,8 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -451,20 +615,45 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -472,8 +661,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -484,7 +674,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -492,10 +681,9 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -528,18 +716,20 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -564,11 +754,26 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -612,10 +817,13 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -625,6 +833,38 @@ google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+n google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 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= @@ -648,6 +888,14 @@ google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -661,22 +909,32 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= +gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -687,3 +945,4 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/handlers/login.go b/handlers/login.go index e8555185..59a60a1f 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -154,12 +154,17 @@ func normalizeLoginURLParam(loginURL *url.URL) (*url.URL, []string, error) { // Still looking for url param if paramKey == "url" { // Found it - parsed, e := url.Parse(loginURL.Query().Get("url")) + parsed, e := url.ParseQuery(param) + if e != nil { return nil, []string{}, e // failure to parse url param } - urlParam = parsed + urlParam, e = url.Parse(parsed.Get("url")) + + if e != nil { + return nil, []string{}, e // failure to parse url param + } } else if !isVouchParam { // Non-vouch param before url param is a stray param log.Infof("Stray param in login request (%s)", paramKey) From 0ea205b2b551054e23c4479442bcfaae0d868818 Mon Sep 17 00:00:00 2001 From: basteln3rk Date: Tue, 9 Aug 2022 13:55:43 +0000 Subject: [PATCH 659/736] restore go.mod and go.sum files --- go.mod | 24 ++-- go.sum | 423 +++++++++++---------------------------------------------- 2 files changed, 93 insertions(+), 354 deletions(-) diff --git a/go.mod b/go.mod index b9b31f8b..0fdb0c36 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,29 @@ module github.com/vouch/vouch-proxy go 1.16 require ( + cloud.google.com/go v0.89.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.6 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 github.com/mailru/easyjson v0.7.7 // indirect - github.com/mitchellh/mapstructure v1.5.0 - github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c + github.com/mitchellh/mapstructure v1.4.1 + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pelletier/go-toml/v2 v2.0.2 // indirect - github.com/spf13/viper v1.12.0 + github.com/spf13/cast v1.4.0 // indirect + github.com/spf13/viper v1.8.1 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/stretchr/testify v1.7.2 - github.com/subosito/gotenv v1.4.0 // indirect + github.com/stretchr/testify v1.7.0 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.21.0 - golang.org/x/net v0.0.0-20220630215102-69896b714898 - golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 - golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect - gopkg.in/ini.v1 v1.66.6 // indirect + go.uber.org/multierr v1.7.0 // indirect + go.uber.org/zap v1.18.1 + golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 ) diff --git a/go.sum b/go.sum index 5ef3f2c1..4f8290c5 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -16,38 +15,23 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.89.0 h1:ZT4GU+y59fC95Mfdn2RtxuzN2gc69dzlVevQK8Ykyqs= +cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -57,59 +41,35 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -117,29 +77,15 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -147,7 +93,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -189,10 +134,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -207,7 +150,6 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -215,66 +157,47 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= @@ -283,140 +206,88 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.0 h1:WhlbjwB9EGCc8W5Rxdkus+wmH2ASRwwTJk6tgHKwdqQ= +github.com/spf13/cast v1.4.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= -github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= -github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -428,24 +299,21 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -471,6 +339,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -485,7 +354,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -493,11 +363,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -516,24 +384,13 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw= -golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -545,18 +402,10 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -568,34 +417,23 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -606,8 +444,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -615,45 +451,20 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8= -golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -661,9 +472,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -674,6 +484,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -681,9 +492,10 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -716,20 +528,18 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -754,26 +564,11 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -817,13 +612,10 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -833,38 +625,6 @@ google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+n google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= 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= @@ -888,14 +648,6 @@ google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -909,32 +661,22 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -945,4 +687,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From c3dd87cb36540243d3b4dee1e7ab958f18d22da3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 12 Aug 2022 11:48:02 -0700 Subject: [PATCH 660/736] improve config error check for private key --- pkg/cfg/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 0cf82cd1..05a08f61 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -431,7 +431,7 @@ func basicTest() error { return fmt.Errorf("%s.jwt.public_key_file should not be set when using signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) } - if len(Cfg.JWT.PrivateKeyFile) > 9 { + if len(Cfg.JWT.PrivateKeyFile) > 0 { return fmt.Errorf("%s.jwt.private_key_file should not be set when using signing method %s", Branding.LCName, Cfg.JWT.SigningMethod) } From aac995ed8e63d129f352906a6f615833d1f6aa47 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 12 Aug 2022 11:50:10 -0700 Subject: [PATCH 661/736] add log message "This is free software with ABSOLUTELY NO WARRANTY." --- main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 7281a910..7d221c74 100644 --- a/main.go +++ b/main.go @@ -136,7 +136,8 @@ func main() { var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) checkTCPPortAvailable(listen) tls := (cfg.Cfg.TLS.Cert != "" && cfg.Cfg.TLS.Key != "") - + logger.Info("Copyright 2020-2022 the " + cfg.Branding.FullName + " Authors") + logger.Warn("This is free software with ABSOLUTELY NO WARRANTY.") logger.Infow("starting "+cfg.Branding.FullName, // "semver": semver, "version", version, From 8eae4e5edc90b83c76fbae92b5f06198911d11cd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 12 Aug 2022 12:54:29 -0700 Subject: [PATCH 662/736] fix #492 build under go 1.16 by forcing use of go.uber.org/atomic@v1.9.0 --- .dockerignore | 1 - go.mod | 2 ++ go.sum | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 73c37b32..7cd8d249 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,6 +13,5 @@ Dockerfile handlers/rice-box.go certs .cover/* -.git .github .whitesource diff --git a/go.mod b/go.mod index 0fdb0c36..f7700e8e 100644 --- a/go.mod +++ b/go.mod @@ -29,3 +29,5 @@ require ( golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 ) + +replace go.uber.org/atomic => go.uber.org/atomic v1.9.0 diff --git a/go.sum b/go.sum index 4f8290c5..26154c9b 100644 --- a/go.sum +++ b/go.sum @@ -296,7 +296,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= From a7461a8cd411e863dd62f99602e247095aef38c6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 12 Aug 2022 13:38:57 -0700 Subject: [PATCH 663/736] fix #493 by upgrading golang.org/x/net --- go.mod | 2 +- go.sum | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f7700e8e..3db6f3de 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.18.1 - golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 + golang.org/x/net v0.0.0-20220812174116-3211cb980234 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 ) diff --git a/go.sum b/go.sum index 26154c9b..ab30573d 100644 --- a/go.sum +++ b/go.sum @@ -390,6 +390,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -460,10 +462,14 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -473,6 +479,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From ca1e30010535add54319f26f112dc81e1d3df4a8 Mon Sep 17 00:00:00 2001 From: squalus Date: Sat, 13 Aug 2022 12:10:41 -0700 Subject: [PATCH 664/736] Add support for listening on unix domain sockets --- CHANGELOG.md | 2 + config/config.yml_example | 9 +++ config/testing/socket_basic.yml | 8 +++ config/testing/socket_mode.yml | 9 +++ main.go | 69 +++++++++++++++++++++-- main_test.go | 99 +++++++++++++++++++++++++++++++++ pkg/cfg/cfg.go | 2 + pkg/cfg/cfg_test.go | 8 +-- 8 files changed, 196 insertions(+), 10 deletions(-) create mode 100644 config/testing/socket_basic.yml create mode 100644 config/testing/socket_mode.yml create mode 100644 main_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 629c72fa..d9ecb053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +- [add support for listening on unix domain sockets](https://github.com/vouch/vouch-proxy/pull/488) + ## v0.37.0 - [allow configurable Write, Read and Idle timeouts for the http server](https://github.com/vouch/vouch-proxy/pull/468) diff --git a/config/config.yml_example b/config/config.yml_example index 7586f5f4..2c1fdead 100644 --- a/config/config.yml_example +++ b/config/config.yml_example @@ -20,6 +20,15 @@ vouch: listen: 0.0.0.0 # VOUCH_LISTEN port: 9090 # VOUCH_PORT + # Listen can specify a Unix domain socket instead. + # listen: unix:/path/to/socket # VOUCH_LISTEN + + # Optionally set the mode of the Unix domain socket. The default if not specified is 0777. + # socket_mode: 0770 # VOUCH_SOCKETMODE + + # Optionally set the group owner of the Unix domain socket. + # socket_group: users # VOUCH_SOCKETGROUP + # The default read, write and idle timeouts are 15 seconds. # If you have a load balancer or proxy in front that has its # own idle timeout, you may need to ensure that the Vouch idle diff --git a/config/testing/socket_basic.yml b/config/testing/socket_basic.yml new file mode 100644 index 00000000..c7cc4500 --- /dev/null +++ b/config/testing/socket_basic.yml @@ -0,0 +1,8 @@ +vouch: + listen: unix:/fake/path/to/socket + +oauth: + provider: indieauth + client_id: http://vouch.github.io + auth_url: https://indielogin.com/auth + callback_url: http://vouch.github.io:9090/auth diff --git a/config/testing/socket_mode.yml b/config/testing/socket_mode.yml new file mode 100644 index 00000000..b784f522 --- /dev/null +++ b/config/testing/socket_mode.yml @@ -0,0 +1,9 @@ +vouch: + listen: unix:/fake/path/to/socket + socket_mode: 0644 + +oauth: + provider: indieauth + client_id: http://vouch.github.io + auth_url: https://indielogin.com/auth + callback_url: http://vouch.github.io:9090/auth diff --git a/main.go b/main.go index 7d221c74..6316547d 100644 --- a/main.go +++ b/main.go @@ -27,11 +27,14 @@ import ( "errors" "flag" "fmt" + "io/fs" "log" "net" "net/http" "os" + "os/user" "strconv" + "strings" "time" // "net/http/pprof" @@ -133,8 +136,12 @@ func configure() { func main() { configure() - var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) - checkTCPPortAvailable(listen) + listenStr := cfg.Cfg.Listen + if !strings.HasPrefix(cfg.Cfg.Listen, "unix:") { + listenStr = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) + checkTCPPortAvailable(listenStr) + } + tls := (cfg.Cfg.TLS.Cert != "" && cfg.Cfg.TLS.Key != "") logger.Info("Copyright 2020-2022 the " + cfg.Branding.FullName + " Authors") logger.Warn("This is free software with ABSOLUTELY NO WARRANTY.") @@ -146,7 +153,7 @@ func main() { "buildhost", host, "branch", branch, "semver", semver, - "listen", scheme[tls]+"://"+listen, + "listen", scheme[tls]+"://"+listenStr, "tls", tls, "document_root", cfg.Cfg.DocumentRoot, "oauth.provider", cfg.GenOAuth.Provider) @@ -195,7 +202,6 @@ func main() { srv := &http.Server{ Handler: router, - Addr: listen, // Good practice: enforce timeouts for servers you create! WriteTimeout: time.Duration(cfg.Cfg.WriteTimeout) * time.Second, ReadTimeout: time.Duration(cfg.Cfg.ReadTimeout) * time.Second, @@ -203,13 +209,64 @@ func main() { ErrorLog: log.New(&fwdToZapWriter{fastlog}, "", 0), } + lis, cleanupFn, err := listen() + if err != nil { + logger.Fatal(err) + } + defer cleanupFn() + if tls { srv.TLSConfig = cfg.TLSConfig(cfg.Cfg.TLS.Profile) - logger.Fatal(srv.ListenAndServeTLS(cfg.Cfg.TLS.Cert, cfg.Cfg.TLS.Key)) + logger.Fatal(srv.ServeTLS(lis, cfg.Cfg.TLS.Cert, cfg.Cfg.TLS.Key)) } else { - logger.Fatal(srv.ListenAndServe()) + logger.Fatal(srv.Serve(lis)) + } + +} + +func listen() (lis net.Listener, cleanupFn func(), err error) { + if !strings.HasPrefix(cfg.Cfg.Listen, "unix:") { + lis, err = net.Listen("tcp", fmt.Sprintf("%s:%d", cfg.Cfg.Listen, cfg.Cfg.Port)) + return lis, func() {}, err } + socketPath := strings.TrimPrefix(cfg.Cfg.Listen, "unix:") + _, err = os.Stat(socketPath) + if err == nil { + if err = os.Remove(socketPath); err != nil { + return nil, nil, fmt.Errorf("remove existing socket file %s: %w", socketPath, err) + } + } else if !os.IsNotExist(err) { + return nil, nil, fmt.Errorf("stat socket file %s: %w", socketPath, err) + } + + lis, err = net.Listen("unix", socketPath) + if err != nil { + return nil, nil, fmt.Errorf("listen %s: %w", socketPath, err) + } + + if cfg.Cfg.SocketMode == 0 { + cfg.Cfg.SocketMode = 0777 + } + mode := fs.FileMode(cfg.Cfg.SocketMode) + if err = os.Chmod(socketPath, mode); err != nil { + return nil, nil, fmt.Errorf("chmod socket file %s %#o", socketPath, mode) + } + + if cfg.Cfg.SocketGroup != "" { + group, err := user.LookupGroup(cfg.Cfg.SocketGroup) + if err != nil { + return nil, nil, fmt.Errorf("lookup socket group: %s %w", cfg.Cfg.SocketGroup, err) + } + gid, err := strconv.Atoi(group.Gid) + if err != nil { + return nil, nil, fmt.Errorf("lookup socket group: invalid gid: %w", err) + } + if err := os.Chown(socketPath, -1, gid); err != nil { + return nil, nil, fmt.Errorf("chown socket: group: %s %w", socketPath, err) + } + } + return lis, func() { _ = os.Remove(socketPath) }, nil } func checkTCPPortAvailable(listen string) { diff --git a/main_test.go b/main_test.go new file mode 100644 index 00000000..4350ab14 --- /dev/null +++ b/main_test.go @@ -0,0 +1,99 @@ +package main + +import ( + "github.com/stretchr/testify/assert" + "github.com/vouch/vouch-proxy/pkg/cfg" + "io/fs" + "os" + "path/filepath" + "strings" + "testing" +) + +func Test_listenUds(t *testing.T) { + setUp(t, "testing/socket_basic.yml") + defer cleanUp() + tempDir, err := os.MkdirTemp("", "") + assert.NoError(t, err) + defer func() { + _ = os.RemoveAll(tempDir) + }() + socketPath := filepath.Join(tempDir, "socket0") + + cfg.Cfg.Listen = strings.Join([]string{"unix", socketPath}, ":") + lis, cleanupFn, err := listen() + assert.NoError(t, err) + assertSocket(t, socketPath) + + fi, err := os.Stat(socketPath) + assert.NoError(t, err) + assert.Equal(t, fs.FileMode(0777), fi.Mode().Perm()) + + assert.NotNil(t, lis) + assert.NoError(t, lis.Close()) + cleanupFn() + _, err = os.Stat(socketPath) + assert.True(t, os.IsNotExist(err)) +} + +// check that socket listening works when the socket path already exists +func Test_listenUds_alreadyExists(t *testing.T) { + setUp(t, "testing/socket_basic.yml") + defer cleanUp() + tempDir, err := os.MkdirTemp("", "") + assert.NoError(t, err) + defer func() { + _ = os.RemoveAll(tempDir) + }() + socketPath := filepath.Join(tempDir, "socket0") + assert.NoError(t, os.WriteFile(socketPath, []byte("stuff in the socket file"), 0600)) + + cfg.Cfg.Listen = strings.Join([]string{"unix", socketPath}, ":") + lis, cleanupFn, err := listen() + assert.NoError(t, err) + assertSocket(t, socketPath) + + assert.NotNil(t, lis) + assert.NoError(t, lis.Close()) + cleanupFn() +} + +// check that the socket mode is adjusted when the SocketMode configuration is present +func Test_listenUds_mode(t *testing.T) { + setUp(t, "config/testing/socket_mode.yml") + defer cleanUp() + tempDir, err := os.MkdirTemp("", "") + assert.NoError(t, err) + defer func() { + _ = os.RemoveAll(tempDir) + }() + socketPath := filepath.Join(tempDir, "socket0") + cfg.Cfg.Listen = strings.Join([]string{"unix", socketPath}, ":") + + lis, cleanupFn, err := listen() + assert.NoError(t, err) + assert.NotNil(t, lis) + assertSocket(t, socketPath) + + stat, err := os.Stat(socketPath) + assert.NoError(t, err) + assert.Equal(t, fs.FileMode(cfg.Cfg.SocketMode), stat.Mode().Perm()) + + assert.NoError(t, lis.Close()) + cleanupFn() +} + +func assertSocket(t *testing.T, socketPath string) { + fi, err := os.Stat(socketPath) + assert.NoError(t, err) + assert.Equal(t, os.ModeSocket, fi.Mode()&os.ModeSocket) +} + +func setUp(t *testing.T, configFile string) { + assert.NoError(t, os.Setenv(cfg.Branding.UCName+"_CONFIG", configFile)) + cfg.InitForTestPurposes() +} + +func cleanUp() { + os.Clearenv() +} diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 05a08f61..5d554996 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -45,6 +45,8 @@ type Config struct { LogLevel string `mapstructure:"logLevel"` Listen string `mapstructure:"listen"` Port int `mapstructure:"port"` + SocketMode int `mapstructure:"socket_mode"` + SocketGroup string `mapstructure:"socket_group"` DocumentRoot string `mapstructure:"document_root" envconfig:"document_root"` WriteTimeout int `mapstructure:"writeTimeout"` ReadTimeout int `mapstructure:"readTimeout"` diff --git a/pkg/cfg/cfg_test.go b/pkg/cfg/cfg_test.go index 712bf1ca..b5ede8e2 100644 --- a/pkg/cfg/cfg_test.go +++ b/pkg/cfg/cfg_test.go @@ -134,12 +134,12 @@ func Test_configureFromEnvCfg(t *testing.T) { senv := []string{"VOUCH_LISTEN", "VOUCH_JWT_ISSUER", "VOUCH_JWT_SECRET", "VOUCH_HEADERS_JWT", "VOUCH_HEADERS_USER", "VOUCH_HEADERS_QUERYSTRING", "VOUCH_HEADERS_REDIRECT", "VOUCH_HEADERS_SUCCESS", "VOUCH_HEADERS_ERROR", "VOUCH_HEADERS_CLAIMHEADER", "VOUCH_HEADERS_ACCESSTOKEN", "VOUCH_HEADERS_IDTOKEN", "VOUCH_COOKIE_NAME", "VOUCH_COOKIE_DOMAIN", - "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT"} + "VOUCH_COOKIE_SAMESITE", "VOUCH_TESTURL", "VOUCH_SESSION_NAME", "VOUCH_SESSION_KEY", "VOUCH_DOCUMENT_ROOT", "VOUCH_SOCKETGROUP"} // array of strings saenv := []string{"VOUCH_DOMAINS", "VOUCH_WHITELIST", "VOUCH_TEAMWHITELIST", "VOUCH_HEADERS_CLAIMS", "VOUCH_TESTURLS", "VOUCH_POST_LOGOUT_REDIRECT_URIS"} // int ienv := []string{"VOUCH_PORT", "VOUCH_JWT_MAXAGE", "VOUCH_COOKIE_MAXAGE", "VOUCH_SESSION_MAXAGE", "VOUCH_WRITETIMEOUT", "VOUCH_READTIMEOUT", - "VOUCH_IDLETIMEOUT"} + "VOUCH_IDLETIMEOUT", "VOUCH_SOCKETMODE"} // bool benv := []string{"VOUCH_ALLOWALLUSERS", "VOUCH_PUBLICACCESS", "VOUCH_JWT_COMPRESS", "VOUCH_COOKIE_SECURE", "VOUCH_COOKIE_HTTPONLY", "VOUCH_TESTING"} @@ -172,11 +172,11 @@ func Test_configureFromEnvCfg(t *testing.T) { scfg := []string{Cfg.Listen, Cfg.JWT.Issuer, Cfg.JWT.Secret, Cfg.Headers.JWT, Cfg.Headers.User, Cfg.Headers.QueryString, Cfg.Headers.Redirect, Cfg.Headers.Success, Cfg.Headers.Error, Cfg.Headers.ClaimHeader, Cfg.Headers.AccessToken, Cfg.Headers.IDToken, Cfg.Cookie.Name, Cfg.Cookie.Domain, - Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, Cfg.DocumentRoot, + Cfg.Cookie.SameSite, Cfg.TestURL, Cfg.Session.Name, Cfg.Session.Key, Cfg.DocumentRoot, Cfg.SocketGroup, } sacfg := [][]string{Cfg.Domains, Cfg.WhiteList, Cfg.TeamWhiteList, Cfg.Headers.Claims, Cfg.TestURLs, Cfg.LogoutRedirectURLs} - icfg := []int{Cfg.Port, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge, Cfg.WriteTimeout, Cfg.ReadTimeout, Cfg.IdleTimeout} + icfg := []int{Cfg.Port, Cfg.JWT.MaxAge, Cfg.Cookie.MaxAge, Cfg.WriteTimeout, Cfg.ReadTimeout, Cfg.IdleTimeout, Cfg.SocketMode} bcfg := []bool{Cfg.AllowAllUsers, Cfg.PublicAccess, Cfg.JWT.Compress, Cfg.Cookie.Secure, Cfg.Cookie.HTTPOnly, From a047ce6b4802e0966e1479ad17992b46c9eca679 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 19 Aug 2022 04:39:24 -0700 Subject: [PATCH 665/736] move copyright and no warranty warning up --- main.go | 2 -- pkg/cfg/cfg.go | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 7d221c74..c29b5165 100644 --- a/main.go +++ b/main.go @@ -136,8 +136,6 @@ func main() { var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port) checkTCPPortAvailable(listen) tls := (cfg.Cfg.TLS.Cert != "" && cfg.Cfg.TLS.Key != "") - logger.Info("Copyright 2020-2022 the " + cfg.Branding.FullName + " Authors") - logger.Warn("This is free software with ABSOLUTELY NO WARRANTY.") logger.Infow("starting "+cfg.Branding.FullName, // "semver": semver, "version", version, diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 05a08f61..a9a5743a 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -177,6 +177,8 @@ type ctxKey int // // so we process these in backwards order (defaults then config file) func Configure() { + logger.Info("Copyright 2020-2022 the " + Branding.FullName + " Authors") + logger.Warn(Branding.FullName + " is free software with ABSOLUTELY NO WARRANTY.") Logging.configureFromCmdline() @@ -203,6 +205,7 @@ func Configure() { fixConfigOptions() Logging.configure() + if err := configureOauth(); err == nil { setProviderDefaults() } From e8e2126c214cb9166124bdffc92fcbe271cdcc07 Mon Sep 17 00:00:00 2001 From: Paul Gier Date: Thu, 25 Aug 2022 10:27:12 -0500 Subject: [PATCH 666/736] update links to config example in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02f10270..4b364b40 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ VP can send the visitor's email, name and other information which the IdP provid ## Installation and Configuration -Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L23-L33) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L81-L82) to `yourdomain.com`. +Vouch Proxy relies on the ability to share a cookie between the Vouch Proxy server and the application it's protecting. Typically this will be done by running Vouch on a subdomain such as `vouch.yourdomain.com` with apps running at `app1.yourdomain.com` and `app2.yourdomain.com`. The protected domain is `.yourdomain.com` and the Vouch Proxy cookie must be set in this domain by setting [vouch.domains](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L38-L48) to include `yourdomain.com` or sometimes by setting [vouch.cookie.domain](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example#L109-L114) to `yourdomain.com`. - `cp ./config/config.yml_example_$OAUTH_PROVIDER ./config/config.yml` - create OAuth credentials for Vouch Proxy at [google](https://console.developers.google.com/apis/credentials) or [github](https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/), etc From c85fac10f18e41f1cba99d8cb1eaea5b89307745 Mon Sep 17 00:00:00 2001 From: Hinnerk Gnutzmann Date: Sat, 26 Nov 2022 17:04:58 +0100 Subject: [PATCH 667/736] docs: add instructions for running tests (on terminal / in vscode) to CONTRIBUTING.md --- CONTRIBUTING.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee3b160c..8d7f05a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,27 @@ +# Setting up a Development Environment + +## Running Tests + +```bash + export VOUCH_ROOT=`pwd` # if not using GOPATH + ./do.sh test +``` + +After running these tests manually once (which creates a test key pair), it is possible to run the tests with VSCode Test Explorer. + +To get it to work, we must set some environment variables in `.vscode/settings.json` which otherwise would be set by `do.sh`: + +```json +{ + "go.testEnvVars": { + "VOUCH_ROOT": "${workspaceFolder}", + "VOUCH_CONFIG": "${workspaceFolder}/config/testing/test_config.yml", + "TEST_PRIVATE_KEY_FILE": "${workspaceFolder}/config/testing/rsa.key", + "TEST_PUBLIC_KEY_FILE": "${workspaceFolder}/config/testing/rsa.pub", + } +} +``` + ### Contributing to Vouch Proxy by submitting a Pull Request **_I really love Vouch Proxy! I wish it did XXXX..._** From e5b8ae10e6953b753b4b9a8e994ab2a0db7794cd Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 20 Jan 2023 15:30:10 -0800 Subject: [PATCH 668/736] go modules update and tidy --- go.mod | 22 +- go.sum | 842 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 765 insertions(+), 99 deletions(-) diff --git a/go.mod b/go.mod index 3db6f3de..5669e62c 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,29 @@ module github.com/vouch/vouch-proxy go 1.16 require ( - cloud.google.com/go v0.89.0 // indirect + cloud.google.com/go/compute v1.15.1 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.9 github.com/gorilla/sessions v1.2.1 github.com/influxdata/tdigest v0.0.1 // indirect github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 github.com/mailru/easyjson v0.7.7 // indirect - github.com/mitchellh/mapstructure v1.4.1 - github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da + github.com/mitchellh/mapstructure v1.5.0 + github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/spf13/cast v1.4.0 // indirect - github.com/spf13/viper v1.8.1 + github.com/spf13/viper v1.15.0 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.8.1 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.18.1 - golang.org/x/net v0.0.0-20220812174116-3211cb980234 - golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.24.0 + golang.org/x/net v0.5.0 + golang.org/x/oauth2 v0.4.0 ) replace go.uber.org/atomic => go.uber.org/atomic v1.9.0 diff --git a/go.sum b/go.sum index ab30573d..6cd2d7ca 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,61 +16,429 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.89.0 h1:ZT4GU+y59fC95Mfdn2RtxuzN2gc69dzlVevQK8Ykyqs= -cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -77,15 +446,29 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -93,6 +476,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -134,8 +518,11 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -150,6 +537,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -157,47 +545,75 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= +github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= @@ -206,88 +622,143 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da h1:qiPWuGGr+1GQE6s9NPSK8iggR/6x/V+0snIoOPYsBgc= -github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= +github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.0 h1:WhlbjwB9EGCc8W5Rxdkus+wmH2ASRwwTJk6tgHKwdqQ= -github.com/spf13/cast v1.4.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= +go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -295,24 +766,31 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -338,7 +816,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -351,10 +828,10 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -362,9 +839,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -383,15 +862,30 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -403,10 +897,22 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -418,22 +924,34 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -445,6 +963,8 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -452,24 +972,52 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -477,13 +1025,18 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -491,7 +1044,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -499,10 +1051,9 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -535,18 +1086,22 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -571,11 +1126,37 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -619,10 +1200,13 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -632,6 +1216,66 @@ google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+n google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +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-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= 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= @@ -655,6 +1299,21 @@ google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -668,22 +1327,30 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -694,3 +1361,4 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 2c6a96690a99a32a016a4b23a2d14d1914eae653 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 20 Jan 2023 17:28:52 -0800 Subject: [PATCH 669/736] go 1.18 from golang v1.16 --> v1.18 golang.org/x/sys now requires go v1.17 or greater. It's become too painful to stay on 1.16 --- .github/workflows/coverage.yml | 2 +- .travis.yml | 2 +- CHANGELOG.md | 4 + Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 2 +- go.mod | 41 +- go.sum | 828 +-------------------------------- 8 files changed, 44 insertions(+), 839 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d06d264d..d5c51bbe 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: # go: ['1.14', '1.15'] - go: ['1.16'] + go: ['1.18'] steps: - uses: actions/setup-go@v2 diff --git a/.travis.yml b/.travis.yml index aaf8a721..06cb1c46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.16" + - "1.18" env: - ISTRAVIS=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 629c72fa..5dc0d984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.38.0 + +- upgrade golang to `v1.18` from `v1.16` + ## v0.37.0 - [allow configurable Write, Read and Idle timeouts for the http server](https://github.com/vouch/vouch-proxy/pull/468) diff --git a/Dockerfile b/Dockerfile index 6639badd..291b9109 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.16 AS builder +FROM golang:1.18 AS builder ARG UID=999 ARG GID=999 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 2f155625..435a98c8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.16 AS builder +FROM golang:1.18 AS builder ARG UID=999 ARG GID=999 diff --git a/do.sh b/do.sh index cced1400..fb0b42a4 100755 --- a/do.sh +++ b/do.sh @@ -13,7 +13,7 @@ fi IMAGE=quay.io/vouch/vouch-proxy:latest ALPINE=quay.io/vouch/vouch-proxy:alpine-latest -GOIMAGE=golang:1.16 +GOIMAGE=golang:1.18 NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 diff --git a/go.mod b/go.mod index 5669e62c..0f4c9128 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,54 @@ module github.com/vouch/vouch-proxy -go 1.16 +go 1.18 require ( - cloud.google.com/go/compute v1.15.1 // indirect - github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect - github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.5.9 github.com/gorilla/sessions v1.2.1 - github.com/influxdata/tdigest v0.0.1 // indirect github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 - github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.5.0 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible github.com/spf13/viper v1.15.0 - github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect github.com/stretchr/testify v1.8.1 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible - go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 golang.org/x/net v0.5.0 golang.org/x/oauth2 v0.4.0 ) -replace go.uber.org/atomic => go.uber.org/atomic v1.9.0 +require ( + cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/influxdata/tdigest v0.0.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 6cd2d7ca..a1de1b51 100644 --- a/go.sum +++ b/go.sum @@ -17,466 +17,65 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -484,8 +83,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -501,10 +98,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -515,19 +110,13 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -538,183 +127,60 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -728,17 +194,13 @@ github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jH github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -748,49 +210,30 @@ github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -816,7 +259,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -827,11 +269,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -839,11 +278,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -860,30 +297,9 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -895,22 +311,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -923,35 +323,19 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -963,8 +347,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -972,71 +354,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1051,7 +386,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1076,7 +410,6 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1085,23 +418,12 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1124,39 +446,6 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1188,7 +477,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1201,81 +489,7 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -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-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= 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= @@ -1289,32 +503,9 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1327,28 +518,16 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1361,4 +540,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 9b8713ca5efca64d9ec296eff48915497f6953bb Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 20 Jan 2023 18:47:09 -0800 Subject: [PATCH 670/736] remove IRC channel mention --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4b364b40..40ac06e8 100644 --- a/README.md +++ b/README.md @@ -467,7 +467,6 @@ TLDR: - and follow the instructions at the end to redact your Nginx config - all of those go into a [gist](https://gist.github.com/) - then [open a new issue](https://github.com/vouch/vouch-proxy/issues/new) in this repository -- or visit our IRC channel [#vouch](irc.libera.chat/#vouch) on libera.chat A bug report can be generated from a docker environment using the `quay.io/vouch/vouch-proxy:alpine` image... From c1925e255acd0103608bbb2d575cdb6e183344d3 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 21 Jan 2023 13:34:02 -0800 Subject: [PATCH 671/736] #488 set socket perm 0660 in .defaults.yml --- .defaults.yml | 2 +- main.go | 3 --- main_test.go | 7 ++++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.defaults.yml b/.defaults.yml index c482ebcd..9b5f8e5e 100644 --- a/.defaults.yml +++ b/.defaults.yml @@ -9,6 +9,7 @@ vouch: testing: false listen: 0.0.0.0 port: 9090 + socket_mode: 0660 # document_root: # domains: allowAllUsers: false @@ -18,7 +19,6 @@ vouch: writeTimeout: 15 readTimeout: 15 idleTimeout: 15 - tls: # cert: # key: diff --git a/main.go b/main.go index be315ace..56934f4d 100644 --- a/main.go +++ b/main.go @@ -243,9 +243,6 @@ func listen() (lis net.Listener, cleanupFn func(), err error) { return nil, nil, fmt.Errorf("listen %s: %w", socketPath, err) } - if cfg.Cfg.SocketMode == 0 { - cfg.Cfg.SocketMode = 0777 - } mode := fs.FileMode(cfg.Cfg.SocketMode) if err = os.Chmod(socketPath, mode); err != nil { return nil, nil, fmt.Errorf("chmod socket file %s %#o", socketPath, mode) diff --git a/main_test.go b/main_test.go index 4350ab14..176e8b01 100644 --- a/main_test.go +++ b/main_test.go @@ -1,13 +1,14 @@ package main import ( - "github.com/stretchr/testify/assert" - "github.com/vouch/vouch-proxy/pkg/cfg" "io/fs" "os" "path/filepath" "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/vouch/vouch-proxy/pkg/cfg" ) func Test_listenUds(t *testing.T) { @@ -27,7 +28,7 @@ func Test_listenUds(t *testing.T) { fi, err := os.Stat(socketPath) assert.NoError(t, err) - assert.Equal(t, fs.FileMode(0777), fi.Mode().Perm()) + assert.Equal(t, fs.FileMode(0660), fi.Mode().Perm()) assert.NotNil(t, lis) assert.NoError(t, lis.Close()) From a676feb8951e1c891289719ea49001180d334d52 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 21 Jan 2023 13:38:18 -0800 Subject: [PATCH 672/736] general note about defaults --- main.go | 2 +- pkg/cfg/cfg.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 56934f4d..7f237595 100644 --- a/main.go +++ b/main.go @@ -243,7 +243,7 @@ func listen() (lis net.Listener, cleanupFn func(), err error) { return nil, nil, fmt.Errorf("listen %s: %w", socketPath, err) } - mode := fs.FileMode(cfg.Cfg.SocketMode) + mode := fs.FileMode(cfg.Cfg.SocketMode) // defaults to 0660 - see .defaults.yml if err = os.Chmod(socketPath, mode); err != nil { return nil, nil, fmt.Errorf("chmod socket file %s %#o", socketPath, mode) } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index b753cd16..9aedba64 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -41,6 +41,7 @@ import ( // in certain situations you'll need to add both a `mapstructure` tag used by viper // as well as a `envconfig` tag used by https://github.com/kelseyhightower/envconfig // though most of the time envconfig will use the struct key's name: VOUCH_PORT VOUCH_JWT_MAXAGE +// default values should be set in .defaults.yml type Config struct { LogLevel string `mapstructure:"logLevel"` Listen string `mapstructure:"listen"` From ee84379bcf6785daa22eb944ab4d34a384b41c35 Mon Sep 17 00:00:00 2001 From: Graeme Meyer <107847353+GraemeMeyerGT@users.noreply.github.com> Date: Wed, 19 Jul 2023 09:41:44 +0100 Subject: [PATCH 673/736] Fix same-page link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40ac06e8..9a853e5d 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) - [Troubleshooting, Support and Feature Requests](#troubleshooting-support-and-feature-requests-read-this-before-submitting-an-issue-at-github) (Read this before submitting an issue at GitHub) - - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#i-m-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp--google-okta-github--) + - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#im-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp-googleoktagithub) - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) - [Contributing to Vouch Proxy](#contributing) - [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) From 3a18fa2fb09f9c85dff155d4b44c0de73ecedbff Mon Sep 17 00:00:00 2001 From: Graeme Meyer <107847353+GraemeMeyerGT@users.noreply.github.com> Date: Wed, 19 Jul 2023 09:42:38 +0100 Subject: [PATCH 674/736] fix same-page link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a853e5d..eb47aefc 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [Troubleshooting, Support and Feature Requests](#troubleshooting-support-and-feature-requests-read-this-before-submitting-an-issue-at-github) (Read this before submitting an issue at GitHub) - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#im-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp-googleoktagithub) - - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay--i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-it-s-still-not-working) + - [Okay, I looked at the issues and have tried some things with my configs but it's still not working](#okay-i-looked-at-the-issues-and-have-tried-some-things-with-my-configs-but-its-still-not-working) - [Contributing to Vouch Proxy](#contributing) - [Advanced Authorization Using OpenResty](#advanced-authorization-using-openresty) - [The flow of login and authentication using Google Oauth](#the-flow-of-login-and-authentication-using-google-oauth) From f8360910e8a50220989c0e3e19c56072c5d15735 Mon Sep 17 00:00:00 2001 From: Graeme Meyer <107847353+GraemeMeyerGT@users.noreply.github.com> Date: Wed, 19 Jul 2023 09:43:33 +0100 Subject: [PATCH 675/736] fix same-page link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb47aefc..2a54be58 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ If Vouch is running on the same host as the Nginx reverse proxy the response tim - [Running from Docker](#running-from-docker) - [Kubernetes Nginx Ingress](#kubernetes-nginx-ingress) - [Compiling from source and running the binary](#compiling-from-source-and-running-the-binary) -- [/login and /logout endpoint redirection](#-login-and--logout-endpoint-redirection) +- [/login and /logout endpoint redirection](#login-and-logout-endpoint-redirection) - [Troubleshooting, Support and Feature Requests](#troubleshooting-support-and-feature-requests-read-this-before-submitting-an-issue-at-github) (Read this before submitting an issue at GitHub) - [I'm getting an infinite redirect loop which returns me to my IdP (Google/Okta/GitHub/...)](#im-getting-an-infinite-redirect-loop-which-returns-me-to-my-idp-googleoktagithub) From 874b373c18813f5c8667c4986a486a2f89eb57cf Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 17 Aug 2023 12:31:04 -0700 Subject: [PATCH 676/736] copyright year++ --- pkg/cfg/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 9aedba64..1083e04e 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -180,7 +180,7 @@ type ctxKey int // // so we process these in backwards order (defaults then config file) func Configure() { - logger.Info("Copyright 2020-2022 the " + Branding.FullName + " Authors") + logger.Info("Copyright 2020-2023 the " + Branding.FullName + " Authors") logger.Warn(Branding.FullName + " is free software with ABSOLUTELY NO WARRANTY.") Logging.configureFromCmdline() From 0516bcfb7e5403bb3566bafe835c9f4a5190cf2a Mon Sep 17 00:00:00 2001 From: Shahbaz Khan Date: Mon, 5 Feb 2024 20:33:43 +0000 Subject: [PATCH 677/736] Added sample config file for keycloak --- .gitignore | 2 +- config/config.yml_example_keycloak | 39 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 config/config.yml_example_keycloak diff --git a/.gitignore b/.gitignore index 48cf5cb6..ead15088 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ vouch-proxy main config/config.yml config/*config.yml -config/config.yml_* +#config/config.yml_* config/google_config.json config/secret !config/testing/* diff --git a/config/config.yml_example_keycloak b/config/config.yml_example_keycloak new file mode 100644 index 00000000..b176c6aa --- /dev/null +++ b/config/config.yml_example_keycloak @@ -0,0 +1,39 @@ + +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with Keycloak + +vouch: + domains: + - yourdomain.com + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # and set vouch.cookie.domain to the domain you wish to protect + # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + # Generic OpenID Connect + # for Keycloak + provider: oidc + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + auth_url: https://{yourKeycloakDomain}/realms/{yourKeycloakRealm}/protocol/openid-connect/auth + token_url: https://{yourKeycloakDomain}/realms/{yourKeycloakRealm}/protocol/openid-connect/token + user_info_url: https://{yourKeycloakDomain}/realms/{yourKeycloakRealm}/protocol/openid-connect/userinfo + scopes: + - openid + - email + - profile + callback_url: http://vouch.yourdomain.com:9090/auth + # you can get values of of auth_url, token_url and user_info_url from https://{yourKeycloakDomain}/realms/{yourKeycloakRealm}/.well-known/openid-configuration + # When configuring client in Keycloak, you should use following values + ## valid redirect: http://vouch.yourdomain.com:9090/auth + ## valid logout: http://vouch.yourdomain.com:9090/logout + ## web origin: http://vouch.yourdomain.com:9090 \ No newline at end of file From f825b4dee542215164e11a5bc2cc268c953d8ba7 Mon Sep 17 00:00:00 2001 From: Shahbaz Khan Date: Mon, 5 Feb 2024 20:34:01 +0000 Subject: [PATCH 678/736] reverting .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ead15088..48cf5cb6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ vouch-proxy main config/config.yml config/*config.yml -#config/config.yml_* +config/config.yml_* config/google_config.json config/secret !config/testing/* From bbeb9a5bbda86e592f9c2462090270e70b6a47a0 Mon Sep 17 00:00:00 2001 From: Shahbaz Khan Date: Mon, 5 Feb 2024 21:31:32 +0000 Subject: [PATCH 679/736] Updated README.md for keycloak sample config --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40ac06e8..cbb0e96a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) - [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) -- Keycloak +- [Keycloak](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_keycloak) - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) - [HomeAssistant](https://developers.home-assistant.io/docs/en/auth_api.html) - [OpenStax](https://github.com/vouch/vouch-proxy/pull/141) From b639ae8213bd97e1779455de42b1db2be2597057 Mon Sep 17 00:00:00 2001 From: Shahbaz Khan Date: Mon, 5 Feb 2024 21:34:08 +0000 Subject: [PATCH 680/736] README.md file update for keycloak sample config --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cbb0e96a..db9e7958 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) - [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) -- [Keycloak](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_keycloak) +- [Keycloak](config/config.yml_keycloak) - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) - [HomeAssistant](https://developers.home-assistant.io/docs/en/auth_api.html) - [OpenStax](https://github.com/vouch/vouch-proxy/pull/141) From 6669758f447d2adbec4e723915a1b152681c159f Mon Sep 17 00:00:00 2001 From: Shahbaz Khan Date: Mon, 5 Feb 2024 21:34:57 +0000 Subject: [PATCH 681/736] Fixed README.md file for keycloak sample config --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db9e7958..64f3e5cb 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) - [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) -- [Keycloak](config/config.yml_keycloak) +- [Keycloak](config/config.yml_example_keycloak) - [OAuth2 Server Library for PHP](https://github.com/vouch/vouch-proxy/issues/99) - [HomeAssistant](https://developers.home-assistant.io/docs/en/auth_api.html) - [OpenStax](https://github.com/vouch/vouch-proxy/pull/141) From 520e8f9c77fc84359af51c7bffdf4fb249d23ff5 Mon Sep 17 00:00:00 2001 From: krumelmonster Date: Wed, 14 Feb 2024 16:10:09 +0100 Subject: [PATCH 682/736] switch config.yml_example_gitea to oidc provider the github provider isn't working for gitea on vouch-proxy 0.18+ https://github.com/vouch/vouch-proxy/issues/346 --- config/config.yml_example_gitea | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.yml_example_gitea b/config/config.yml_example_gitea index 532d530f..3f805f93 100644 --- a/config/config.yml_example_gitea +++ b/config/config.yml_example_gitea @@ -20,10 +20,10 @@ oauth: # replace "gitea.yourdomain.com" with the domain your Gitea instance runs on # create a new OAuth application at: # https://gitea.yourdomain.com/user/settings/applications - provider: github + provider: oidc client_id: xxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx auth_url: https://gitea.yourdomain.com/login/oauth/authorize token_url: https://gitea.yourdomain.com/login/oauth/access_token - user_info_url: https://gitea.yourdomain.com/api/v1/user?token= + user_info_url: https://gitea.yourdomain.com/login/oauth/userinfo callback_url: https://yourdomain.com/auth From ad2e9ac8ad03e7d22cdbb44abc47c74ad046071a Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Sat, 23 Mar 2024 09:20:18 -0700 Subject: [PATCH 683/736] upgrade golang to v1.22 --- .github/workflows/coverage.yml | 2 +- .travis.yml | 2 +- CHANGELOG.md | 4 + Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 2 +- go.mod | 52 ++-- go.sum | 535 +++++---------------------------- 8 files changed, 107 insertions(+), 494 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d5c51bbe..f2472311 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: # go: ['1.14', '1.15'] - go: ['1.18'] + go: ['1.22'] steps: - uses: actions/setup-go@v2 diff --git a/.travis.yml b/.travis.yml index 06cb1c46..fe1d7698 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.18" + - "1.22" env: - ISTRAVIS=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 71e380e7..fe104235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.40.0 + +- upgrade golang to `v1.22` from `v1.18` + ## v0.39.0 - [add support for listening on unix domain sockets](https://github.com/vouch/vouch-proxy/pull/488) diff --git a/Dockerfile b/Dockerfile index 291b9109..86eb1449 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.18 AS builder +FROM golang:1.22 AS builder ARG UID=999 ARG GID=999 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 435a98c8..fe674a36 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.18 AS builder +FROM golang:1.22 AS builder ARG UID=999 ARG GID=999 diff --git a/do.sh b/do.sh index fb0b42a4..31397661 100755 --- a/do.sh +++ b/do.sh @@ -13,7 +13,7 @@ fi IMAGE=quay.io/vouch/vouch-proxy:latest ALPINE=quay.io/vouch/vouch-proxy:alpine-latest -GOIMAGE=golang:1.18 +GOIMAGE=golang:1.22 NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 diff --git a/go.mod b/go.mod index 0f4c9128..9b3e5f69 100644 --- a/go.mod +++ b/go.mod @@ -1,54 +1,56 @@ module github.com/vouch/vouch-proxy -go 1.18 +go 1.22 require ( github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.5.9 - github.com/gorilla/sessions v1.2.1 + github.com/google/go-cmp v0.6.0 + github.com/gorilla/sessions v1.2.2 github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 github.com/mitchellh/mapstructure v1.5.0 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.1 + github.com/spf13/viper v1.18.2 + github.com/stretchr/testify v1.9.0 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible - go.uber.org/zap v1.24.0 - golang.org/x/net v0.5.0 - golang.org/x/oauth2 v0.4.0 + go.uber.org/zap v1.27.0 + golang.org/x/net v0.22.0 + golang.org/x/oauth2 v0.18.0 ) require ( - cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/gorilla/securecookie v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect - github.com/subosito/gotenv v1.4.2 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.9.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a1de1b51..f1f1b26c 100644 --- a/go.sum +++ b/go.sum @@ -1,165 +1,46 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 h1:XSik/ETzj52cVbZcv7tJuUFX14XzvRX0te26UaKY0Aw= github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45/go.mod h1:FULZ2B7LE0CUYtI8XLMYxI58AF9M6MTg6nWmZvWoFHQ= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -171,372 +52,98 @@ github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= +github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -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/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -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= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 0b2fdb60955dae710f6f52bd21a582dfe36fbad0 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Tue, 4 Apr 2023 23:47:16 -0700 Subject: [PATCH 684/736] Implemented Discord provider --- handlers/handlers.go | 3 ++ pkg/cfg/oauth.go | 27 ++++++++++++- pkg/providers/discord/discord.go | 66 ++++++++++++++++++++++++++++++++ pkg/structs/structs.go | 23 ++++++++++- 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 pkg/providers/discord/discord.go diff --git a/handlers/handlers.go b/handlers/handlers.go index 6dae94e3..1a46895e 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -14,6 +14,7 @@ import ( "net/http" "github.com/gorilla/sessions" + "github.com/vouch/vouch-proxy/pkg/providers/discord" "go.uber.org/zap" "golang.org/x/oauth2" @@ -88,6 +89,8 @@ func getProvider() Provider { return openid.Provider{} case cfg.Providers.Alibaba: return alibaba.Provider{} + case cfg.Providers.Discord: + return discord.Provider{} default: // shouldn't ever reach this since cfg checks for a properly configure `oauth.provider` log.Fatal("oauth.provider appears to be misconfigured, please check your config") diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 56442d64..e7e2f644 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -44,6 +44,7 @@ var ( OpenStax: "openstax", Nextcloud: "nextcloud", Alibaba: "alibaba", + Discord: "discord", } ) @@ -59,6 +60,7 @@ type OAuthProviders struct { OpenStax string Nextcloud string Alibaba string + Discord string } // oauth config items endoint for access @@ -122,7 +124,8 @@ func oauthBasicTest() error { GenOAuth.Provider != Providers.OIDC && GenOAuth.Provider != Providers.OpenStax && GenOAuth.Provider != Providers.Nextcloud && - GenOAuth.Provider != Providers.Alibaba { + GenOAuth.Provider != Providers.Alibaba && + GenOAuth.Provider != Providers.Discord { return errors.New("configuration error: Unknown oauth provider: " + GenOAuth.Provider) } // OAuthconfig Checks @@ -188,6 +191,9 @@ func setProviderDefaults() { } else if GenOAuth.Provider == Providers.IndieAuth { GenOAuth.CodeChallengeMethod = "S256" configureOAuthClient() + } else if GenOAuth.Provider == Providers.Discord { + setDefaultsDiscord() + configureOAuthClient() } else { // OIDC, OpenStax, Nextcloud configureOAuthClient() @@ -270,6 +276,25 @@ func setDefaultsGitHub() { GenOAuth.CodeChallengeMethod = "S256" } +func setDefaultsDiscord() { + // log.Info("configuring GitHub OAuth") + if GenOAuth.AuthURL == "" { + GenOAuth.AuthURL = "https://discord.com/oauth2/authorize" + } + if GenOAuth.TokenURL == "" { + GenOAuth.TokenURL = "https://discord.com/api/oauth2/token" + } + if GenOAuth.UserInfoURL == "" { + GenOAuth.UserInfoURL = "https://discord.com/api/users/@me" + } + if len(GenOAuth.Scopes) == 0 { + //Required for UserInfo URL + //https://discord.com/developers/docs/resources/user#get-current-user + GenOAuth.Scopes = []string{"identify"} + } + GenOAuth.CodeChallengeMethod = "S256" +} + func configureOAuthClient() { log.Infof("configuring %s OAuth with Endpoint %s", GenOAuth.Provider, GenOAuth.AuthURL) OAuthClient = &oauth2.Config{ diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go new file mode 100644 index 00000000..e6c293ec --- /dev/null +++ b/pkg/providers/discord/discord.go @@ -0,0 +1,66 @@ +/* + +Copyright 2020 The Vouch Proxy Authors. +Use of this source code is governed by The MIT License (MIT) that +can be found in the LICENSE file. Software distributed under The +MIT License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. + +*/ + +package discord + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "golang.org/x/oauth2" + + "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/vouch/vouch-proxy/pkg/providers/common" + "github.com/vouch/vouch-proxy/pkg/structs" + "go.uber.org/zap" +) + +// Provider provider specific functions +type Provider struct{} + +var log *zap.SugaredLogger + +// Configure see main.go configure() +func (Provider) Configure() { + log = cfg.Logging.Logger +} + +// GetUserInfo provider specific call to get userinfomation +func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { + client, _, err := common.PrepareTokensAndClient(r, ptokens, true, opts...) + if err != nil { + return err + } + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) + if err != nil { + return err + } + defer func() { + if err := userinfo.Body.Close(); err != nil { + rerr = err + } + }() + data, _ := ioutil.ReadAll(userinfo.Body) + log.Infof("Discord userinfo body: %s", string(data)) + if err = common.MapClaims(data, customClaims); err != nil { + log.Error(err) + return err + } + discordUser := structs.DiscordUser{} + if err = json.Unmarshal(data, &discordUser); err != nil { + log.Error(err) + return err + } + discordUser.PrepareUserData() + user.Username = discordUser.PreparedUsername + user.Email = discordUser.Email + return nil +} diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index bccc0180..5abcaca7 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -10,7 +10,10 @@ OR CONDITIONS OF ANY KIND, either express or implied. package structs -import "strconv" +import ( + "fmt" + "strconv" +) // CustomClaims Temporary struct storing custom claims until JWT creation. type CustomClaims struct { @@ -148,7 +151,7 @@ type Contact struct { Verified bool `json:"is_verified"` } -//OpenStaxUser is a retrieved and authenticated user from OpenStax Accounts +// OpenStaxUser is a retrieved and authenticated user from OpenStax Accounts type OpenStaxUser struct { User Contacts []Contact `json:"contact_infos"` @@ -240,3 +243,19 @@ type PTokens struct { PAccessToken string PIdToken string } + +// DiscordUser deserializes values from the Discord User Object: https://discord.com/developers/docs/resources/user#user-object-user-structure +type DiscordUser struct { + Id string `json:"id"` + Username string `json:"username"` + Discriminator string `json:"discriminator"` + PreparedUsername string + Email string `json:"email"` + Verified bool `json:"verified"` +} + +// PrepareUserData copies the Username and Discriminator in the format that Discord guarantees to be unique +// https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" +func (u *DiscordUser) PrepareUserData() { + u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) +} From 89a7df304c2c165bed903c9177d5660611362763 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Wed, 5 Apr 2023 00:17:36 -0700 Subject: [PATCH 685/736] Discord should also ask for the email by default --- pkg/cfg/oauth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index e7e2f644..9fdde680 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -290,7 +290,7 @@ func setDefaultsDiscord() { if len(GenOAuth.Scopes) == 0 { //Required for UserInfo URL //https://discord.com/developers/docs/resources/user#get-current-user - GenOAuth.Scopes = []string{"identify"} + GenOAuth.Scopes = []string{"identify", "email"} } GenOAuth.CodeChallengeMethod = "S256" } From a1eecf6477fc8676854d3e584030bf40c4d42a63 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Mon, 26 Jun 2023 23:17:36 -0700 Subject: [PATCH 686/736] Use global name if discriminator has been cleared --- pkg/providers/discord/discord.go | 7 +++++-- pkg/structs/structs.go | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index e6c293ec..b4431174 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -12,7 +12,7 @@ package discord import ( "encoding/json" - "io/ioutil" + "io" "net/http" "golang.org/x/oauth2" @@ -48,7 +48,10 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, err := io.ReadAll(userinfo.Body) + if err != nil { + return err + } log.Infof("Discord userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 5abcaca7..70ed0b13 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -249,13 +249,18 @@ type DiscordUser struct { Id string `json:"id"` Username string `json:"username"` Discriminator string `json:"discriminator"` - PreparedUsername string + GlobalName string `json:"global_name"` Email string `json:"email"` Verified bool `json:"verified"` + PreparedUsername string } // PrepareUserData copies the Username and Discriminator in the format that Discord guarantees to be unique // https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" func (u *DiscordUser) PrepareUserData() { - u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) + if u.Discriminator != "0" { + u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) + return + } + u.PreparedUsername = u.GlobalName } From a27c1d7a31ea7f9736358b69c4f0af22474bfbff Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Mon, 26 Jun 2023 23:39:48 -0700 Subject: [PATCH 687/736] Use the username instead of global name for ident --- pkg/structs/structs.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 70ed0b13..5db89df1 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -258,9 +258,8 @@ type DiscordUser struct { // PrepareUserData copies the Username and Discriminator in the format that Discord guarantees to be unique // https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" func (u *DiscordUser) PrepareUserData() { + u.PreparedUsername = u.Username if u.Discriminator != "0" { u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) - return } - u.PreparedUsername = u.GlobalName } From c9d5b76aef4e4297e3380905dff23cff213e14ad Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Wed, 5 Apr 2023 00:25:39 -0700 Subject: [PATCH 688/736] Added changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe104235..c8b2d38b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +* Implement a Discord provider that uses `Username` as the username to match against in the `whiteList` config + * Or uses `Username#Discriminator` if the Discriminator is present + * Or uses ID if `discord_use_ids` is set + ## v0.40.0 - upgrade golang to `v1.22` from `v1.18` From 89c0df9864842e76865ffd4dac0bfad88405a53e Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Wed, 5 Apr 2023 00:26:29 -0700 Subject: [PATCH 689/736] Add Discord provider config example --- config/config.yml_example_discord | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 config/config.yml_example_discord diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord new file mode 100644 index 00000000..f5259947 --- /dev/null +++ b/config/config.yml_example_discord @@ -0,0 +1,22 @@ + +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with OpenID Connect (such as okta) + +vouch: + domains: + - yourdomain.com + # whiteList is a list of username#discriminator that will allow a login if allowAllUsers is false + whiteList: + - loganintech#0001 + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + provider: discord + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + callback_url: http://vouch.yourdomain.com:9090/auth From 4bef475d9a75dcec9211b4384ad0c87ff74d1b5d Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Wed, 3 May 2023 13:12:19 -0700 Subject: [PATCH 690/736] Discord changed their minds on unique usernames, so let's change our implementation to reflect that --- config/config.yml_example_discord | 4 ++-- pkg/providers/discord/discord.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord index f5259947..bcc3b8d9 100644 --- a/config/config.yml_example_discord +++ b/config/config.yml_example_discord @@ -5,9 +5,9 @@ vouch: domains: - yourdomain.com - # whiteList is a list of username#discriminator that will allow a login if allowAllUsers is false + # whiteList is a list of user ids that will allow a login if allowAllUsers is false whiteList: - - loganintech#0001 + - 12341234123412345 cookie: # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index b4431174..4c6c984e 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -12,7 +12,7 @@ package discord import ( "encoding/json" - "io" + "io/ioutil" "net/http" "golang.org/x/oauth2" From c2506bd857095cb818201b093d9e0cd15e6201ca Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Dec 2023 00:07:05 -0800 Subject: [PATCH 691/736] Updates with some messaging on new vs old username formats --- config/config.yml_example_discord | 8 +++++--- pkg/structs/structs.go | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord index bcc3b8d9..1d4fd3cc 100644 --- a/config/config.yml_example_discord +++ b/config/config.yml_example_discord @@ -1,13 +1,15 @@ # Vouch Proxy configuration -# bare minimum to get Vouch Proxy running with OpenID Connect (such as okta) +# bare minimum to get Vouch Proxy running with Discord as an OpenID Provider vouch: domains: - yourdomain.com - # whiteList is a list of user ids that will allow a login if allowAllUsers is false + # whiteList is a list of usernames that will allow a login if allowAllUsers is false whiteList: - - 12341234123412345 + - loganintech + # If the user still hasn't chosen a new username, the old username#discrimnator format will work + - LoganInTech#1203 cookie: # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 5db89df1..e709237b 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -255,8 +255,10 @@ type DiscordUser struct { PreparedUsername string } -// PrepareUserData copies the Username and Discriminator in the format that Discord guarantees to be unique -// https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" +// PrepareUserData copies the Username to PreparedUsername. If the Discriminator is present that is +// appended to the Username in the format "Username#Discriminator" to match the old format of Discord usernames +// Previous format which is being phased out: https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" +// Details about the new username requirements: https://support.discord.com/hc/en-us/articles/12620128861463 func (u *DiscordUser) PrepareUserData() { u.PreparedUsername = u.Username if u.Discriminator != "0" { From 648c98ebe49af361a9db9182a22a5b08f1ece1ee Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Mar 2024 13:12:05 -0700 Subject: [PATCH 692/736] Rebased --- pkg/providers/discord/discord.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index 4c6c984e..82d12a73 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -12,15 +12,16 @@ package discord import ( "encoding/json" - "io/ioutil" + "io" "net/http" "golang.org/x/oauth2" + "go.uber.org/zap" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" - "go.uber.org/zap" ) // Provider provider specific functions From 4539c4942d2e0967068232ce8110671d76c19646 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Mar 2024 13:37:45 -0700 Subject: [PATCH 693/736] Updated discord provider to optionally match user IDs instead of username --- config/config.yml_example_discord | 7 +++++++ pkg/cfg/oauth.go | 6 +++++- pkg/providers/discord/discord.go | 4 +++- pkg/structs/structs.go | 26 ++++++++++++++++++-------- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord index 1d4fd3cc..3323d5a9 100644 --- a/config/config.yml_example_discord +++ b/config/config.yml_example_discord @@ -7,10 +7,15 @@ vouch: - yourdomain.com # whiteList is a list of usernames that will allow a login if allowAllUsers is false whiteList: + # The default behavior matches the Discord user's username - loganintech + # If the user still hasn't chosen a new username, the old username#discrimnator format will work - LoganInTech#1203 + # If discord_use_ids is set to true, you must use the user's ID + - 81255545020878848 + cookie: # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) secure: false @@ -22,3 +27,5 @@ oauth: client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx client_secret: xxxxxxxxxxxxxxxxxxxxxxxx callback_url: http://vouch.yourdomain.com:9090/auth + ## Uncomment this to match users based on their Discord ID + # discord_use_ids: true diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 9fdde680..3992f891 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -85,6 +85,7 @@ type oauthConfig struct { PreferredDomain string `mapstructure:"preferredDomain"` AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` + DiscordUseIDs bool `mapstructure:"discord_use_ids" envconfig:"discord_use_ids"` } type oauthClaimsConfig struct { @@ -322,7 +323,10 @@ func checkCallbackConfig(url string) error { } } if !found { - return fmt.Errorf("configuration error: oauth.callback_url (%s) must be within a configured domains where the cookie will be set: either `vouch.domains` %s or `vouch.cookie.domain` %s", url, Cfg.Domains, Cfg.Cookie.Domain) + return fmt.Errorf("configuration error: oauth.callback_url (%s) must be within a configured domains where the cookie will be set: either `vouch.domains` %s or `vouch.cookie.domain` %s", + url, + Cfg.Domains, + Cfg.Cookie.Domain) } return nil diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index 82d12a73..fb2d1089 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -25,7 +25,9 @@ import ( ) // Provider provider specific functions -type Provider struct{} +type Provider struct { + UseSecureIDs bool +} var log *zap.SugaredLogger diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index e709237b..33979f94 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -13,6 +13,8 @@ package structs import ( "fmt" "strconv" + + "github.com/vouch/vouch-proxy/pkg/cfg" ) // CustomClaims Temporary struct storing custom claims until JWT creation. @@ -246,20 +248,28 @@ type PTokens struct { // DiscordUser deserializes values from the Discord User Object: https://discord.com/developers/docs/resources/user#user-object-user-structure type DiscordUser struct { - Id string `json:"id"` - Username string `json:"username"` - Discriminator string `json:"discriminator"` - GlobalName string `json:"global_name"` - Email string `json:"email"` - Verified bool `json:"verified"` + Id string `json:"id"` + Username string `json:"username"` + Discriminator string `json:"discriminator"` + GlobalName string `json:"global_name"` + Email string `json:"email"` + Verified bool `json:"verified"` + PreparedUsername string } -// PrepareUserData copies the Username to PreparedUsername. If the Discriminator is present that is -// appended to the Username in the format "Username#Discriminator" to match the old format of Discord usernames +// PrepareUserData copies the Username to PreparedUsername. +// If the provider is configured to use IDs, the ID is copied to PreparedUsername. +// If the Discriminator is present that is appended to the Username in the format "Username#Discriminator" +// to match the old format of Discord usernames // Previous format which is being phased out: https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" // Details about the new username requirements: https://support.discord.com/hc/en-us/articles/12620128861463 func (u *DiscordUser) PrepareUserData() { + if cfg.GenOAuth.DiscordUseIDs { + u.PreparedUsername = u.Id + return + } + u.PreparedUsername = u.Username if u.Discriminator != "0" { u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) From 6bacd9e53e2f46a33edf47fb5dda64c746441b04 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Mar 2024 13:38:28 -0700 Subject: [PATCH 694/736] Remove unused provider prop --- pkg/providers/discord/discord.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index fb2d1089..82d12a73 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -25,9 +25,7 @@ import ( ) // Provider provider specific functions -type Provider struct { - UseSecureIDs bool -} +type Provider struct{} var log *zap.SugaredLogger From d30df4ffc825be9d48f5c5fcd21da73d9fa7b4c9 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Mar 2024 13:43:42 -0700 Subject: [PATCH 695/736] Use example discord user ID instead of my actual user ID --- config/config.yml_example_discord | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord index 3323d5a9..6a197b45 100644 --- a/config/config.yml_example_discord +++ b/config/config.yml_example_discord @@ -14,7 +14,7 @@ vouch: - LoganInTech#1203 # If discord_use_ids is set to true, you must use the user's ID - - 81255545020878848 + - 12345678901234567 cookie: # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) From 2e8f4cfed630d7fcbe757a6812fbb408daef4f66 Mon Sep 17 00:00:00 2001 From: Logan Saso Date: Sun, 24 Mar 2024 13:48:34 -0700 Subject: [PATCH 696/736] Comments --- pkg/cfg/oauth.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 3992f891..73a96eeb 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -85,7 +85,9 @@ type oauthConfig struct { PreferredDomain string `mapstructure:"preferredDomain"` AzureToken string `mapstructure:"azure_token" envconfig:"azure_token"` CodeChallengeMethod string `mapstructure:"code_challenge_method" envconfig:"code_challenge_method"` - DiscordUseIDs bool `mapstructure:"discord_use_ids" envconfig:"discord_use_ids"` + // DiscordUseIDs defaults to false, maintaining the more common username checking behavior + // If set to true, match the Discord user's ID instead of their username + DiscordUseIDs bool `mapstructure:"discord_use_ids" envconfig:"discord_use_ids"` } type oauthClaimsConfig struct { From dd1d72c80d248333ec54190d7f93f9888e9029b9 Mon Sep 17 00:00:00 2001 From: Mark McWhirter <8041254+mcmarkj@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:45:48 +0100 Subject: [PATCH 697/736] Correct handling typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40ac06e8..0f58a47f 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ The variable `VOUCH_CONFIG` can be used to set an alternate location for the con All Vouch Proxy configuration items are documented in [config/config.yml_example](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example) - [Cacheing of the Vouch Proxy `/validate` response in Nginx](https://github.com/vouch/vouch-proxy/issues/76#issuecomment-464028743) -- [Handleing `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) +- [Handling `OPTIONS` requests when protecting an API with Vouch Proxy](https://github.com/vouch/vouch-proxy/issues/216) - [Validation by GitHub Team or GitHub Org](https://github.com/vouch/vouch-proxy/pull/205) - [Running VP on a Raspberry Pi using the ARM based Docker image](https://github.com/vouch/vouch-proxy/pull/247) - [Kubernetes architecture post ingress](https://github.com/vouch/vouch-proxy/pull/263#issuecomment-628297832) From 802d968d864e547d343fe4ad726d959771f9fae6 Mon Sep 17 00:00:00 2001 From: Ahmed Aladeeb Date: Fri, 30 Aug 2024 16:36:34 +0300 Subject: [PATCH 698/736] feat: upgrade go version from 1.21 to 1.23 to solve the gorilla/sessions compatibility issues https://github.com/gorilla/sessions/releases/tag/v1.4.0 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 2 +- go.mod | 2 +- go.sum | 7 +++++++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 86eb1449..031083a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.22 AS builder +FROM golang:1.23 AS builder ARG UID=999 ARG GID=999 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index fe674a36..19f650c8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.22 AS builder +FROM golang:1.23 AS builder ARG UID=999 ARG GID=999 diff --git a/do.sh b/do.sh index 31397661..8d0aca67 100755 --- a/do.sh +++ b/do.sh @@ -13,7 +13,7 @@ fi IMAGE=quay.io/vouch/vouch-proxy:latest ALPINE=quay.io/vouch/vouch-proxy:alpine-latest -GOIMAGE=golang:1.22 +GOIMAGE=golang:1.23 NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 diff --git a/go.mod b/go.mod index 9b3e5f69..154b25a3 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vouch/vouch-proxy -go 1.22 +go 1.23 require ( github.com/golang-jwt/jwt v3.2.2+incompatible diff --git a/go.sum b/go.sum index f1f1b26c..a6ce2281 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -24,6 +25,7 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= @@ -41,7 +43,9 @@ github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -58,6 +62,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -91,6 +96,7 @@ github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5 github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -142,6 +148,7 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 8a3ee3f465a9e00972b6b37fc9e42cdfe0a914e8 Mon Sep 17 00:00:00 2001 From: Ahmed Aladeeb Date: Fri, 30 Aug 2024 17:07:26 +0300 Subject: [PATCH 699/736] add the change to the changelog unreleased section --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe104235..547be45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +- upgrade golang to `v1.23` from `v1.22` + ## v0.40.0 - upgrade golang to `v1.22` from `v1.18` From 2270a1eceacc89f6ef723b733466c12639cdaab0 Mon Sep 17 00:00:00 2001 From: Ahmed Aladeeb Date: Fri, 30 Aug 2024 19:29:00 +0300 Subject: [PATCH 700/736] add the new version in the ci yml files --- .github/workflows/coverage.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f2472311..4c9cff1a 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: # go: ['1.14', '1.15'] - go: ['1.22'] + go: ['1.23'] steps: - uses: actions/setup-go@v2 diff --git a/.travis.yml b/.travis.yml index fe1d7698..a2d3709c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.22" + - "1.23" env: - ISTRAVIS=true From 012b2fdb6182f659735f1f43ecaadf5b4a3d038f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Tue, 1 Oct 2024 14:58:01 -0700 Subject: [PATCH 701/736] upgrade golang to v1.23 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 547be45d..ab56ab94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.41.0 + - upgrade golang to `v1.23` from `v1.22` ## v0.40.0 From d152926006c4ad1430097db1329dfc71b5165630 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Wed, 9 Apr 2025 12:34:06 +0100 Subject: [PATCH 702/736] add alpine builds of vouch-proxy images --- .../workflows/docker-release-quayio-alpine.yml | 17 +++++++++++++---- .github/workflows/docker-release-quayio.yml | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/docker-release-quayio-alpine.yml b/.github/workflows/docker-release-quayio-alpine.yml index 4c2a1d1f..ca76c3cc 100644 --- a/.github/workflows/docker-release-quayio-alpine.yml +++ b/.github/workflows/docker-release-quayio-alpine.yml @@ -17,14 +17,20 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v2 - + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker repository uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: registry: ${{ env.DOCKER_REPO }} username: ${{ secrets.QUAYIO_ROBOT_USERNAME }} password: ${{ secrets.QUAYIO_ROBOT_PASSWORD }} - + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@a67f45cb0f8e65cf693a0bc5bfa1c5057c623030 @@ -36,7 +42,7 @@ jobs: type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - + - name: Build and push Docker image using Dockerfile.alpine uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: @@ -44,4 +50,7 @@ jobs: context: . push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} + platforms: | + linux/amd64 + linux/arm64 \ No newline at end of file diff --git a/.github/workflows/docker-release-quayio.yml b/.github/workflows/docker-release-quayio.yml index 04969fde..aecd768b 100644 --- a/.github/workflows/docker-release-quayio.yml +++ b/.github/workflows/docker-release-quayio.yml @@ -17,14 +17,20 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v2 - + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker repository uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: registry: ${{ env.DOCKER_REPO }} username: ${{ secrets.QUAYIO_ROBOT_USERNAME }} password: ${{ secrets.QUAYIO_ROBOT_PASSWORD }} - + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 @@ -34,7 +40,7 @@ jobs: type=ref,event=branch type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - + - name: Build and push Docker image using Dockerfile uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: @@ -42,3 +48,6 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + platforms: | + linux/amd64 + linux/arm64 From 3179aeb69c4a83bf90625ef1ef98659257106e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Paul?= Date: Wed, 9 Apr 2025 19:04:29 +0200 Subject: [PATCH 703/736] docs: add pocket-id config example --- .gitignore | 1 + README.md | 1 + config/config.yml_example_pocket-id | 37 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 config/config.yml_example_pocket-id diff --git a/.gitignore b/.gitignore index 48cf5cb6..1ba86c2a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ main config/config.yml config/*config.yml config/config.yml_* +!config.yml_example_pocket-id config/google_config.json config/secret !config/testing/* diff --git a/README.md b/README.md index 40ac06e8..67e206f8 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [OpenStax](https://github.com/vouch/vouch-proxy/pull/141) - [Ory Hydra](https://github.com/vouch/vouch-proxy/issues/288) - [Nextcloud](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/oauth2.html) +- [Pocket ID](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_pocket-id) - most other OpenID Connect (OIDC) providers Please do let us know when you have deployed Vouch Proxy with your preffered IdP or library so we can update the list. diff --git a/config/config.yml_example_pocket-id b/config/config.yml_example_pocket-id new file mode 100644 index 00000000..c92ba73d --- /dev/null +++ b/config/config.yml_example_pocket-id @@ -0,0 +1,37 @@ + +# Vouch Proxy configuration +# bare minimum to get Vouch Proxy running with pocket-id + +vouch: + # domains: + # valid domains that the jwt cookies can be set into + # the callback_urls will be to these domains + domains: + - yourdomain.com + - yourotherdomain.com + + # - OR - + # instead of setting specific domains you may prefer to allow all users... + # set allowAllUsers: true to use Vouch Proxy to just accept anyone who can authenticate at the configured provider + # and set vouch.cookie.domain to the domain you wish to protect + # allowAllUsers: true + + cookie: + # allow the jwt/cookie to be set into http://yourdomain.com (defaults to true, requiring https://yourdomain.com) + secure: false + # vouch.cookie.domain must be set when enabling allowAllUsers + # domain: yourdomain.com + +oauth: + # pocket-id + provider: oidc + client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx + client_secret: xxxxxxxxxxxxxxxxxxxxxxxx + auth_url: https://{yourPocketIdDomain}/authorize + token_url: https://{yourPocketIdDomain}/api/oidc/token + user_info_url: https://{yourPocketIdDomain}/api/oidc/userinfo + scopes: + - openid + - email + - profile + callback_url: http://vouch.{yourdomain.com}/auth From 1b805b65dc50b74bfb8785e0d961c2bcf7b1668a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Paul?= Date: Thu, 10 Apr 2025 13:17:18 +0200 Subject: [PATCH 704/736] refactor: clean gitignore rules --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 1ba86c2a..1d2cc5fa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,6 @@ vouch-proxy main config/config.yml config/*config.yml -config/config.yml_* -!config.yml_example_pocket-id config/google_config.json config/secret !config/testing/* From c885c1a7b6903adb474f036f89d3dfb84abe5d37 Mon Sep 17 00:00:00 2001 From: Will Keaney Date: Wed, 14 May 2025 12:57:53 -0400 Subject: [PATCH 705/736] 597: Update mapstructure dependency to match viper. mitchellh/mapstructure is no longer maintained and has been forked to go-viper/mapstructure. As such, viper.Unmarshal no longer supports mitchellh/mapstructure as the DecoderConfigOption argument. Update the mapstructure dependency to use viper's version instead. --- pkg/cfg/cfg.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 1083e04e..ca681256 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -28,7 +28,7 @@ import ( "github.com/golang-jwt/jwt" "github.com/kelseyhightower/envconfig" - "github.com/mitchellh/mapstructure" + "github.com/go-viper/mapstructure/v2" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" "go.uber.org/zap" @@ -374,8 +374,8 @@ func fixConfigOptions() { } // use viper and mapstructure check to see if -// https://pkg.go.dev/github.com/spf13/viper@v1.6.3?tab=doc#Unmarshal -// https://pkg.go.dev/github.com/mitchellh/mapstructure?tab=doc#DecoderConfig +// https://pkg.go.dev/github.com/spf13/viper@v1.20.1?tab=doc#Unmarshal +// https://github.com/go-viper/mapstructure func checkConfigFileWellFormed() error { opt := func(dc *mapstructure.DecoderConfig) { dc.ErrorUnused = true From 93dc5d0e94a2b3a9152d0a07eae4c9f51794997b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=B3r=C3=A1nt=20Pint=C3=A9r?= Date: Wed, 18 Jun 2025 08:17:32 +0200 Subject: [PATCH 706/736] Fix typo The commented-out line was missing a semicolon. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40ac06e8..0c7fd1c4 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ server { # forward authorized requests to your service protectedapp.yourdomain.com proxy_pass http://127.0.0.1:8080; # you may need to set these variables in this block as per https://github.com/vouch/vouch-proxy/issues/26#issuecomment-425215810 - # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user + # auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user; # auth_request_set $auth_resp_x_vouch_idp_claims_groups $upstream_http_x_vouch_idp_claims_groups; # auth_request_set $auth_resp_x_vouch_idp_claims_given_name $upstream_http_x_vouch_idp_claims_given_name; From 6cf86add6dc3fe18a3b2e01eefeabe61bc460093 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Wed, 23 Jul 2025 09:58:29 +1000 Subject: [PATCH 707/736] Fix Github authentication --- pkg/cfg/oauth.go | 6 +++--- pkg/providers/github/github.go | 20 ++++++++------------ pkg/providers/github/github_test.go | 18 +++++++++--------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 56442d64..176a89f1 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -250,13 +250,13 @@ func setDefaultsGitHub() { GenOAuth.TokenURL = github.Endpoint.TokenURL } if GenOAuth.UserInfoURL == "" { - GenOAuth.UserInfoURL = "https://api.github.com/user?access_token=" + GenOAuth.UserInfoURL = "https://api.github.com/user" } if GenOAuth.UserTeamURL == "" { - GenOAuth.UserTeamURL = "https://api.github.com/orgs/:org_id/teams/:team_slug/memberships/:username?access_token=" + GenOAuth.UserTeamURL = "https://api.github.com/orgs/:org_id/teams/:team_slug/memberships/:username" } if GenOAuth.UserOrgURL == "" { - GenOAuth.UserOrgURL = "https://api.github.com/orgs/:org_id/members/:username?access_token=" + GenOAuth.UserOrgURL = "https://api.github.com/orgs/:org_id/members/:username" } if len(GenOAuth.Scopes) == 0 { // https://github.com/vouch/vouch-proxy/issues/63 diff --git a/pkg/providers/github/github.go b/pkg/providers/github/github.go index 8fa7e932..c4440ad7 100644 --- a/pkg/providers/github/github.go +++ b/pkg/providers/github/github.go @@ -37,17 +37,13 @@ func (Provider) Configure() { } // GetUserInfo github user info, calls github api for org and teams -// https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-authorization-options-for-oauth-apps/ func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *structs.CustomClaims, ptokens *structs.PTokens, opts ...oauth2.AuthCodeOption) (rerr error) { - client, ptoken, err := me.PrepareTokensAndClient(r, ptokens, true) + client, _, err := me.PrepareTokensAndClient(r, ptokens, true, opts...) if err != nil { - // http.Error(w, err.Error(), http.StatusBadRequest) return err } - log.Debugf("ptoken.AccessToken: %s", ptoken.AccessToken) - userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL + ptoken.AccessToken) + userinfo, err := client.Get(cfg.GenOAuth.UserInfoURL) if err != nil { - // http.Error(w, err.Error(), http.StatusBadRequest) return err } defer func() { @@ -99,9 +95,9 @@ func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims var err error isMember := false if team != "" { - isMember, err = getTeamMembershipStateFromGitHub(client, user, org, team, ptoken) + isMember, err = getTeamMembershipStateFromGitHub(client, user, org, team) } else { - isMember, err = getOrgMembershipStateFromGitHub(client, user, org, ptoken) + isMember, err = getOrgMembershipStateFromGitHub(client, user, org) } if err != nil { return err @@ -121,9 +117,9 @@ func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims return nil } -func getOrgMembershipStateFromGitHub(client *http.Client, user *structs.User, orgID string, ptoken *oauth2.Token) (isMember bool, rerr error) { +func getOrgMembershipStateFromGitHub(client *http.Client, user *structs.User, orgID string) (isMember bool, rerr error) { replacements := strings.NewReplacer(":org_id", orgID, ":username", user.Username) - orgMembershipResp, err := client.Get(replacements.Replace(cfg.GenOAuth.UserOrgURL) + ptoken.AccessToken) + orgMembershipResp, err := client.Get(replacements.Replace(cfg.GenOAuth.UserOrgURL)) if err != nil { log.Error(err) return false, err @@ -149,9 +145,9 @@ func getOrgMembershipStateFromGitHub(client *http.Client, user *structs.User, or } } -func getTeamMembershipStateFromGitHub(client *http.Client, user *structs.User, orgID string, team string, ptoken *oauth2.Token) (isMember bool, rerr error) { +func getTeamMembershipStateFromGitHub(client *http.Client, user *structs.User, orgID string, team string) (isMember bool, rerr error) { replacements := strings.NewReplacer(":org_id", orgID, ":team_slug", team, ":username", user.Username) - membershipStateResp, err := client.Get(replacements.Replace(cfg.GenOAuth.UserTeamURL) + ptoken.AccessToken) + membershipStateResp, err := client.Get(replacements.Replace(cfg.GenOAuth.UserTeamURL)) if err != nil { log.Error(err) return false, err diff --git a/pkg/providers/github/github_test.go b/pkg/providers/github/github_test.go index 1caf5abc..d895d354 100644 --- a/pkg/providers/github/github_test.go +++ b/pkg/providers/github/github_test.go @@ -105,7 +105,7 @@ func TestGetTeamMembershipStateFromGitHubActive(t *testing.T) { setUp() mockResponse(regexMatcher(".*"), http.StatusOK, map[string]string{}, []byte("{\"state\": \"active\"}")) - isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1", token) + isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1") assert.Nil(t, err) assert.True(t, isMember) @@ -115,7 +115,7 @@ func TestGetTeamMembershipStateFromGitHubInactive(t *testing.T) { setUp() mockResponse(regexMatcher(".*"), http.StatusOK, map[string]string{}, []byte("{\"state\": \"inactive\"}")) - isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1", token) + isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1") assert.Nil(t, err) assert.False(t, isMember) @@ -125,7 +125,7 @@ func TestGetTeamMembershipStateFromGitHubNotAMember(t *testing.T) { setUp() mockResponse(regexMatcher(".*"), http.StatusNotFound, map[string]string{}, []byte("")) - isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1", token) + isMember, err := getTeamMembershipStateFromGitHub(client, user, "org1", "team1") assert.Nil(t, err) assert.False(t, isMember) @@ -135,12 +135,12 @@ func TestGetOrgMembershipStateFromGitHubNotFound(t *testing.T) { setUp() mockResponse(regexMatcher(".*"), http.StatusNotFound, map[string]string{}, []byte("")) - isMember, err := getOrgMembershipStateFromGitHub(client, user, "myorg", token) + isMember, err := getOrgMembershipStateFromGitHub(client, user, "myorg") assert.Nil(t, err) assert.False(t, isMember) - expectedOrgMembershipURL := "https://api.github.com/orgs/myorg/members/" + user.Username + "?access_token=" + token.AccessToken + expectedOrgMembershipURL := "https://api.github.com/orgs/myorg/members/" + user.Username assertURLCalled(t, expectedOrgMembershipURL) } @@ -151,12 +151,12 @@ func TestGetOrgMembershipStateFromGitHubNoOrgAccess(t *testing.T) { mockResponse(regexMatcher(".*orgs/myorg/members.*"), http.StatusFound, map[string]string{"Location": location}, []byte("")) mockResponse(regexMatcher(".*orgs/myorg/public_members.*"), http.StatusNoContent, map[string]string{}, []byte("")) - isMember, err := getOrgMembershipStateFromGitHub(client, user, "myorg", token) + isMember, err := getOrgMembershipStateFromGitHub(client, user, "myorg") assert.Nil(t, err) assert.True(t, isMember) - expectedOrgMembershipURL := "https://api.github.com/orgs/myorg/members/" + user.Username + "?access_token=" + token.AccessToken + expectedOrgMembershipURL := "https://api.github.com/orgs/myorg/members/" + user.Username assertURLCalled(t, expectedOrgMembershipURL) expectedOrgPublicMembershipURL := "https://api.github.com/orgs/myorg/public_members/" + user.Username @@ -178,7 +178,7 @@ func TestGetUserInfo(t *testing.T) { Login: "myusername", Picture: "avatar-url", }) - mockResponse(urlEquals(cfg.GenOAuth.UserInfoURL+token.AccessToken), http.StatusOK, map[string]string{}, userInfoContent) + mockResponse(urlEquals(cfg.GenOAuth.UserInfoURL), http.StatusOK, map[string]string{}, userInfoContent) cfg.Cfg.TeamWhiteList = append(cfg.Cfg.TeamWhiteList, "myOtherOrg", "myorg/myteam") @@ -194,6 +194,6 @@ func TestGetUserInfo(t *testing.T) { assert.Equal(t, "myusername", user.Username) assert.Equal(t, []string{"myOtherOrg", "myorg/myteam"}, user.TeamMemberships) - expectedTeamMembershipURL := "https://api.github.com/orgs/myorg/teams/myteam/memberships/myusername?access_token=" + token.AccessToken + expectedTeamMembershipURL := "https://api.github.com/orgs/myorg/teams/myteam/memberships/myusername" assertURLCalled(t, expectedTeamMembershipURL) } From b1e6a81611827cb4b281ae5a96d8eb8c2d797333 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 11:58:30 -0700 Subject: [PATCH 708/736] skip performance tests by default --- do.sh | 13 ++++++++++++- handlers/validate_test.go | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/do.sh b/do.sh index 8d0aca67..2dec29f2 100755 --- a/do.sh +++ b/do.sh @@ -181,6 +181,15 @@ coveragereport() { } test() { + export SKIPPERFTEST=true; + _tests +} + +test_perf() { + _tests +} + +_tests() { if [ -z "$VOUCH_CONFIG" ]; then export VOUCH_CONFIG="$SDIR/config/testing/test_config.yml" fi @@ -382,7 +391,8 @@ usage() { $0 drun [args] - run docker container $0 dbuildalpine - build docker container for alpine $0 drunalpine [args] - run docker container for alpine - $0 test [./pkg_test.go] - run go tests (defaults to all tests) + $0 test [./pkg_test.go] - run go tests (defaults to NOT run performance tests) + $0 test_perf - run go tests including performance tests $0 test_logging - test the logging output $0 coverage - coverage test $0 coveragereport - coverage report published to .cover/coverage.html @@ -421,6 +431,7 @@ case "$ARG" in |'stats' \ |'usage' \ |'bug_report' \ + |'test_perf' \ |'test_logging' \ |'license' \ |'profile' \ diff --git a/handlers/validate_test.go b/handlers/validate_test.go index 1889d6f9..b1364749 100644 --- a/handlers/validate_test.go +++ b/handlers/validate_test.go @@ -65,6 +65,9 @@ func TestValidateRequestHandlerPerf(t *testing.T) { if _, ok := os.LookupEnv("ISTRAVIS"); ok { t.Skip("travis doesn't like perf tests, skipping") } + if _, ok := os.LookupEnv("SKIPPERFTEST"); ok { + t.Skip("skipping performance tests") + } setUp("/config/testing/handler_email.yml") user := &structs.User{Username: "testuser", Email: "test@example.com", Name: "Test Name"} From d9fae8e0c7ab019aa00ea67d53db53f786744639 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 12:08:52 -0700 Subject: [PATCH 709/736] cleanup warnings, mostly from gostaticcheck --- go.mod | 46 +++---- go.sum | 125 +++++-------------- handlers/auth_test.go | 3 + handlers/handlers_test.go | 7 +- handlers/login.go | 7 +- pkg/capturewriter/capturewriter.go | 4 +- pkg/cfg/cfg.go | 8 +- pkg/cfg/jwt.go | 6 +- pkg/cfg/logging.go | 3 +- pkg/cookie/cookie.go | 2 +- pkg/domains/domains.go | 5 +- pkg/healthcheck/healthcheck.go | 4 +- pkg/jwtmanager/jwtmanager.go | 10 +- pkg/providers/adfs/adfs.go | 4 +- pkg/providers/alibaba/alibaba.go | 4 +- pkg/providers/azure/azure.go | 5 +- pkg/providers/common/common.go | 2 +- pkg/providers/github/github.go | 9 +- pkg/providers/google/google.go | 7 +- pkg/providers/homeassistant/homeassistant.go | 9 +- pkg/providers/indieauth/indieauth.go | 7 +- pkg/providers/nextcloud/nextcloud.go | 7 +- pkg/providers/openid/openid.go | 7 +- pkg/providers/openstax/openstax.go | 7 +- pkg/responses/responses.go | 10 +- 25 files changed, 124 insertions(+), 184 deletions(-) diff --git a/go.mod b/go.mod index 154b25a3..c21e3514 100644 --- a/go.mod +++ b/go.mod @@ -1,56 +1,50 @@ module github.com/vouch/vouch-proxy -go 1.23 +go 1.23.0 + +toolchain go1.23.2 require ( + github.com/go-viper/mapstructure/v2 v2.4.0 github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/go-cmp v0.6.0 - github.com/gorilla/sessions v1.2.2 + github.com/google/go-cmp v0.7.0 + github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 github.com/karupanerura/go-mock-http-response v0.0.0-20171201120521-7c242a447d45 github.com/kelseyhightower/envconfig v1.4.0 - github.com/mitchellh/mapstructure v1.5.0 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/spf13/viper v1.18.2 - github.com/stretchr/testify v1.9.0 + github.com/spf13/viper v1.20.1 + github.com/stretchr/testify v1.10.0 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible go.uber.org/zap v1.27.0 - golang.org/x/net v0.22.0 - golang.org/x/oauth2 v0.18.0 + golang.org/x/net v0.42.0 + golang.org/x/oauth2 v0.30.0 ) require ( - cloud.google.com/go/compute v1.25.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.7.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sagikazarmark/locafero v0.9.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/afero v1.14.0 // indirect + github.com/spf13/cast v1.9.2 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a6ce2281..8eff9038 100644 --- a/go.sum +++ b/go.sum @@ -1,37 +1,28 @@ -cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= -cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q= github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= -github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= +github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -46,111 +37,63 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI= github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= -github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= +github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= +github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB7jMeiKJB31jlResI= github.com/tsenart/vegeta v12.7.0+incompatible h1:sGlrv11EMxQoKOlDuMWR23UdL90LE5VlhKw/6PWkZmU= github.com/tsenart/vegeta v12.7.0+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= +golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/auth_test.go b/handlers/auth_test.go index 2846c504..f074553c 100644 --- a/handlers/auth_test.go +++ b/handlers/auth_test.go @@ -50,6 +50,9 @@ func TestCallbackHandlerDocumentRoot(t *testing.T) { // grab the state from the session cookie to session, err := sessstore.Get(reqLogin, cfg.Cfg.Session.Name) state := session.Values["state"].(string) + if err != nil { + t.Fatal(err) + } // now mimic an IdP returning the state variable back to us reqAuth, err := http.NewRequest("GET", cfg.Cfg.DocumentRoot+"/auth?state="+state, nil) diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 8c399c61..3cd91598 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -17,7 +17,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "golang.org/x/oauth2" "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/cookie" @@ -27,9 +26,9 @@ import ( "github.com/vouch/vouch-proxy/pkg/structs" ) -var ( - token = &oauth2.Token{AccessToken: "123"} -) +// var ( +// token = &oauth2.Token{AccessToken: "123"} +// ) // setUp load config file and then call Configure() for dependent packages func setUp(configFile string) { diff --git a/handlers/login.go b/handlers/login.go index 59a60a1f..66c041e3 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -29,7 +29,7 @@ import ( ) // see https://github.com/vouch/vouch-proxy/issues/282 -var errTooManyRedirects = errors.New("Too many unsuccessful authorization attempts for the requested URL") +var errTooManyRedirects = errors.New("too many unsuccessful authorization attempts for the requested URL") const failCountLimit = 6 @@ -204,7 +204,7 @@ func getValidRequestedURL(r *http.Request) (string, error) { } if err != nil { - return "", fmt.Errorf("Not a valid login URL: %w %s", errInvalidURL, err) + return "", fmt.Errorf("not a valid login URL: %w %s", errInvalidURL, err) } if u == nil || u.String() == "" { @@ -301,10 +301,9 @@ func appendCodeChallenge(session sessions.Session) { switch strings.ToUpper(cfg.GenOAuth.CodeChallengeMethod) { case "S256": codeChallenge = CodeVerifier.CodeChallengeS256() - break case "PLAIN": - codeChallenge = CodeVerifier.CodeChallengePlain() // TODO support plain text code challenge + //codeChallenge = CodeVerifier.CodeChallengePlain() log.Fatal("plain code challenge method is not supported") return default: diff --git a/pkg/capturewriter/capturewriter.go b/pkg/capturewriter/capturewriter.go index e6a9a756..5133d05b 100644 --- a/pkg/capturewriter/capturewriter.go +++ b/pkg/capturewriter/capturewriter.go @@ -22,12 +22,12 @@ import ( // and then pull it out later for logging // https://play.golang.org/p/wPHaX9DH-Ik -var logger *zap.SugaredLogger +// var logger *zap.SugaredLogger var log *zap.Logger // Configure see main.go configure() func Configure() { - logger = cfg.Logging.Logger + // logger = cfg.Logging.Logger log = cfg.Logging.FastLogger } diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index ca681256..7a0e98bb 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -16,8 +16,8 @@ import ( "errors" "flag" "fmt" + "io" "io/fs" - "io/ioutil" "net/http" "os" "os/user" @@ -26,9 +26,9 @@ import ( "reflect" "strings" + "github.com/go-viper/mapstructure/v2" "github.com/golang-jwt/jwt" "github.com/kelseyhightower/envconfig" - "github.com/go-viper/mapstructure/v2" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" "go.uber.org/zap" @@ -633,7 +633,7 @@ func DecryptionKey() (interface{}, error) { return nil, fmt.Errorf("error opening Key %s: %s", Cfg.JWT.PublicKeyFile, err) } - keyBytes, err := ioutil.ReadAll(f) + keyBytes, err := io.ReadAll(f) if err != nil { return nil, fmt.Errorf("error reading Key: %s", err) } @@ -666,7 +666,7 @@ func SigningKey() (interface{}, error) { return nil, fmt.Errorf("error opening RSA Key %s: %s", Cfg.JWT.PrivateKeyFile, err) } - keyBytes, err := ioutil.ReadAll(f) + keyBytes, err := io.ReadAll(f) if err != nil { return nil, fmt.Errorf("error reading Key: %s", err) } diff --git a/pkg/cfg/jwt.go b/pkg/cfg/jwt.go index bead1961..0d4e5e78 100644 --- a/pkg/cfg/jwt.go +++ b/pkg/cfg/jwt.go @@ -11,13 +11,13 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( - "io/ioutil" + "os" securerandom "github.com/theckman/go-securerandom" ) func getOrGenerateJWTSecret() string { - b, err := ioutil.ReadFile(secretFile) + b, err := os.ReadFile(secretFile) if err == nil { log.Info("jwt.secret read from " + secretFile) } else { @@ -33,7 +33,7 @@ func getOrGenerateJWTSecret() string { log.Fatal(err) } b = []byte(rstr) - err = ioutil.WriteFile(secretFile, b, 0600) + err = os.WriteFile(secretFile, b, 0600) if err != nil { log.Error(err) logSysInfo() diff --git a/pkg/cfg/logging.go b/pkg/cfg/logging.go index 9005e565..902eac40 100644 --- a/pkg/cfg/logging.go +++ b/pkg/cfg/logging.go @@ -11,7 +11,6 @@ OR CONDITIONS OF ANY KIND, either express or implied. package cfg import ( - "fmt" "os" "strconv" @@ -106,7 +105,7 @@ func (logging) configure() { // then we weren't configured via command line, check the config file if !viper.IsSet(Branding.LCName + ".logLevel") { // then we weren't configured via the config file, set the default - Cfg.LogLevel = fmt.Sprintf("%s", Logging.DefaultLogLevel) + Cfg.LogLevel = Logging.DefaultLogLevel.String() } if Cfg.LogLevel != Logging.AtomicLogLevel.Level().String() { diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index b544eaf9..75354dd2 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -186,7 +186,7 @@ func SameSite() http.SameSite { case "strict": sameSite = http.SameSiteStrictMode case "none": - if cfg.Cfg.Cookie.Secure == false { + if !cfg.Cfg.Cookie.Secure { log.Error("SameSite cookie attribute with sameSite=none should also be specified with secure=true.") } sameSite = http.SameSiteNoneMode diff --git a/pkg/domains/domains.go b/pkg/domains/domains.go index 32fbfbd4..ecbb62ea 100644 --- a/pkg/domains/domains.go +++ b/pkg/domains/domains.go @@ -56,10 +56,7 @@ func IsUnderManagement(email string) bool { } match := Matches(split[1]) - if match != "" { - return true - } - return false + return match != "" } // ByLengthDesc sort from diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go index be974171..6636289f 100644 --- a/pkg/healthcheck/healthcheck.go +++ b/pkg/healthcheck/healthcheck.go @@ -13,7 +13,7 @@ package healthcheck import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "os" @@ -46,7 +46,7 @@ func healthcheck() { // #nosec - turn off gosec checking which flags `http.Get(url)` resp, err := http.Get(url) if err == nil { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) resp.Body.Close() if err == nil { var result map[string]interface{} diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index cdbd5c39..b80caae5 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -16,7 +16,7 @@ import ( "encoding/base64" "errors" "fmt" - "io/ioutil" + "io" "net/http" "strings" "time" @@ -110,12 +110,12 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs ss, err := token.SignedString(key) if ss == "" || err != nil { - return "", fmt.Errorf("New JWT: signed token error: %s", err) + return "", fmt.Errorf("new JWT: signed token error: %s", err) } if cfg.Cfg.JWT.Compress { ss, err = compressAndEncodeTokenString(ss) if ss == "" || err != nil { - return "", fmt.Errorf("New JWT: compressed token error: %w", err) + return "", fmt.Errorf("new JWT: compressed token error: %w", err) } } return ss, nil @@ -149,7 +149,7 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { return jwt.ParseWithClaims(tokenString, &VouchClaims{}, func(token *jwt.Token) (interface{}, error) { // return jwt.ParseWithClaims(tokenString, &VouchClaims{}, func(token *jwt.Token) (interface{}, error) { if token.Method != jwt.GetSigningMethod(cfg.Cfg.JWT.SigningMethod) { - return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return key, nil @@ -196,7 +196,7 @@ func decodeAndDecompressTokenString(encgzipss string) string { if err := zr.Close(); err != nil { log.Debugf("Error decoding token: %v", err) } - ss, _ := ioutil.ReadAll(zr) + ss, _ := io.ReadAll(zr) return string(ss) } diff --git a/pkg/providers/adfs/adfs.go b/pkg/providers/adfs/adfs.go index 32c2cebf..ed2d7da2 100644 --- a/pkg/providers/adfs/adfs.go +++ b/pkg/providers/adfs/adfs.go @@ -14,7 +14,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "regexp" @@ -81,7 +81,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) tokenRes := adfsTokenRes{} if err := json.Unmarshal(data, &tokenRes); err != nil { diff --git a/pkg/providers/alibaba/alibaba.go b/pkg/providers/alibaba/alibaba.go index e9577246..6503ee3e 100644 --- a/pkg/providers/alibaba/alibaba.go +++ b/pkg/providers/alibaba/alibaba.go @@ -12,7 +12,7 @@ package alibaba import ( "encoding/json" - "io/ioutil" + "io" "net/http" "golang.org/x/oauth2" @@ -48,7 +48,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("Alibaba userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/providers/azure/azure.go b/pkg/providers/azure/azure.go index 16a1355f..b9387802 100644 --- a/pkg/providers/azure/azure.go +++ b/pkg/providers/azure/azure.go @@ -14,10 +14,11 @@ import ( "encoding/base64" "encoding/json" "fmt" - "golang.org/x/oauth2" "net/http" "strings" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -53,7 +54,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s } else if cfg.GenOAuth.AzureToken == "id_token" { tokenParts = strings.Split(ptokens.PIdToken, ".") } else { - err = fmt.Errorf("Azure Token not access_token or id_token") + err = fmt.Errorf("azure Token not access_token or id_token") log.Error(err) return err } diff --git a/pkg/providers/common/common.go b/pkg/providers/common/common.go index 461b1d84..01b82e08 100644 --- a/pkg/providers/common/common.go +++ b/pkg/providers/common/common.go @@ -68,7 +68,7 @@ func MapClaims(claims []byte, customClaims *structs.CustomClaims) error { found = true } } - if found == false { + if !found { delete(m, k) } } diff --git a/pkg/providers/github/github.go b/pkg/providers/github/github.go index c4440ad7..51a0f77e 100644 --- a/pkg/providers/github/github.go +++ b/pkg/providers/github/github.go @@ -13,7 +13,7 @@ package github import ( "encoding/json" "errors" - "io/ioutil" + "io" "net/http" "strings" @@ -51,7 +51,7 @@ func (me Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("github userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) @@ -130,6 +130,9 @@ func getOrgMembershipStateFromGitHub(client *http.Client, user *structs.User, or location := orgMembershipResp.Header.Get("Location") if location != "" { orgMembershipResp, err = client.Get(location) + if err != nil { + log.Error(err) + } } } @@ -158,7 +161,7 @@ func getTeamMembershipStateFromGitHub(client *http.Client, user *structs.User, o } }() if membershipStateResp.StatusCode == 200 { - data, _ := ioutil.ReadAll(membershipStateResp.Body) + data, _ := io.ReadAll(membershipStateResp.Body) log.Infof("github team membership body: ", string(data)) ghTeamState := structs.GitHubTeamMembershipState{} if err = json.Unmarshal(data, &ghTeamState); err != nil { diff --git a/pkg/providers/google/google.go b/pkg/providers/google/google.go index dbfa0b01..35d571db 100644 --- a/pkg/providers/google/google.go +++ b/pkg/providers/google/google.go @@ -12,10 +12,11 @@ package google import ( "encoding/json" - "golang.org/x/oauth2" - "io/ioutil" + "io" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -47,7 +48,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("google userinfo body: ", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/providers/homeassistant/homeassistant.go b/pkg/providers/homeassistant/homeassistant.go index c2b7ad0b..ca6b457c 100644 --- a/pkg/providers/homeassistant/homeassistant.go +++ b/pkg/providers/homeassistant/homeassistant.go @@ -11,23 +11,22 @@ OR CONDITIONS OF ANY KIND, either express or implied. package homeassistant import ( - "golang.org/x/oauth2" "net/http" - "github.com/vouch/vouch-proxy/pkg/cfg" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" - "go.uber.org/zap" ) // Provider provider specific functions type Provider struct{} -var log *zap.SugaredLogger +// var log *zap.SugaredLogger // Configure see main.go configure() func (Provider) Configure() { - log = cfg.Logging.Logger + // log = cfg.Logging.Logger } // GetUserInfo provider specific call to get userinfomation diff --git a/pkg/providers/indieauth/indieauth.go b/pkg/providers/indieauth/indieauth.go index d602fcf3..7aa41937 100644 --- a/pkg/providers/indieauth/indieauth.go +++ b/pkg/providers/indieauth/indieauth.go @@ -13,11 +13,12 @@ package indieauth import ( "bytes" "encoding/json" - "golang.org/x/oauth2" - "io/ioutil" + "io" "mime/multipart" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -90,7 +91,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("indieauth userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/providers/nextcloud/nextcloud.go b/pkg/providers/nextcloud/nextcloud.go index c6979798..b912730d 100644 --- a/pkg/providers/nextcloud/nextcloud.go +++ b/pkg/providers/nextcloud/nextcloud.go @@ -12,10 +12,11 @@ package nextcloud import ( "encoding/json" - "golang.org/x/oauth2" - "io/ioutil" + "io" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -47,7 +48,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("Ocs userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/providers/openid/openid.go b/pkg/providers/openid/openid.go index bdc6bb7f..d5c9c5e7 100644 --- a/pkg/providers/openid/openid.go +++ b/pkg/providers/openid/openid.go @@ -12,10 +12,11 @@ package openid import ( "encoding/json" - "golang.org/x/oauth2" - "io/ioutil" + "io" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -47,7 +48,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("OpenID userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/providers/openstax/openstax.go b/pkg/providers/openstax/openstax.go index b9ccf24d..6c7f7687 100644 --- a/pkg/providers/openstax/openstax.go +++ b/pkg/providers/openstax/openstax.go @@ -12,10 +12,11 @@ package openstax import ( "encoding/json" - "golang.org/x/oauth2" - "io/ioutil" + "io" "net/http" + "golang.org/x/oauth2" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/providers/common" "github.com/vouch/vouch-proxy/pkg/structs" @@ -47,7 +48,7 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s rerr = err } }() - data, _ := ioutil.ReadAll(userinfo.Body) + data, _ := io.ReadAll(userinfo.Body) log.Infof("OpenStax userinfo body: %s", string(data)) if err = common.MapClaims(data, customClaims); err != nil { log.Error(err) diff --git a/pkg/responses/responses.go b/pkg/responses/responses.go index 24dd65c4..87013333 100644 --- a/pkg/responses/responses.go +++ b/pkg/responses/responses.go @@ -11,7 +11,6 @@ OR CONDITIONS OF ANY KIND, either express or implied. package responses import ( - "errors" "html/template" "net/http" @@ -31,17 +30,17 @@ type Index struct { var ( indexTemplate *template.Template - errorTemplate *template.Template log *zap.SugaredLogger - fastlog *zap.Logger + // fastlog *zap.Logger - errNotAuthorized = errors.New("not authorized") + // errorTemplate *template.Template + // errNotAuthorized = errors.New("not authorized") ) // Configure see main.go configure() func Configure() { log = cfg.Logging.Logger - fastlog = cfg.Logging.FastLogger + // fastlog = cfg.Logging.FastLogger log.Debugf("responses.Configure() attempting to parse embedded templates") indexTemplate = template.Must(template.ParseFS(cfg.Templates, "templates/index.tmpl")) @@ -133,5 +132,4 @@ func addErrandCancelRequest(r *http.Request) { ctx = context.WithValue(ctx, cfg.ErrCtxKey, true) *r = *r.Clone(ctx) cancel() // we're done - return } From c9753b43034612dfa1614fa5d584e74a979c0537 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 12:38:53 -0700 Subject: [PATCH 710/736] v0.42.0 changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab56ab94..edfb79b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.42.0 + +- [fix auth to github](https://github.com/vouch/vouch-proxy/pull/600) +- cleanup of minor issues flagged by gostaticcheck + ## v0.41.0 - upgrade golang to `v1.23` from `v1.22` From 398eaa17a47736ed00aaf5fb92b2b8854b27b18f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 12:43:32 -0700 Subject: [PATCH 711/736] typo on PR link 600 -> 601 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edfb79b7..cddd9d78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Coming soon! Please document any work in progress here as part of your PR. It wi ## v0.42.0 -- [fix auth to github](https://github.com/vouch/vouch-proxy/pull/600) +- [fix auth to github](https://github.com/vouch/vouch-proxy/pull/601) - cleanup of minor issues flagged by gostaticcheck ## v0.41.0 From 3f38690681d0399524f115687c45ac68f8979878 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 13:16:53 -0700 Subject: [PATCH 712/736] add links to Pocket ID --- config/config.yml_example_pocket-id | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/config.yml_example_pocket-id b/config/config.yml_example_pocket-id index c92ba73d..f733b190 100644 --- a/config/config.yml_example_pocket-id +++ b/config/config.yml_example_pocket-id @@ -2,6 +2,10 @@ # Vouch Proxy configuration # bare minimum to get Vouch Proxy running with pocket-id +# Pocket ID +# https://pocket-id.org +# https://github.com/pocket-id/pocket-id + vouch: # domains: # valid domains that the jwt cookies can be set into From 38d2ded3bc4c21e676a53347fbc0c3a236ab4512 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 13:17:48 -0700 Subject: [PATCH 713/736] ignore config/config.yml_ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1d2cc5fa..7d708432 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ vouch-proxy main config/config.yml config/*config.yml +config/config.yml_* +!config/config.yml_example_pocket-id config/google_config.json config/secret !config/testing/* From 3e1b76ff0e4ecac54d62aae7611942b693694208 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 14:11:03 -0700 Subject: [PATCH 714/736] add docker multi-platform / multi-arch info --- CHANGELOG.md | 4 ++++ README.md | 2 ++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab56ab94..017db0bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.43.0 + +- support multi-platform / multi-arch builds for published Docker images including `linux/amd64` and `linux/arm64` + ## v0.41.0 - upgrade golang to `v1.23` from `v1.22` diff --git a/README.md b/README.md index 40ac06e8..9e9b0076 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,8 @@ an `alpine` based container built from `Dockerfile.alpine` - `quay.io/vouch/vouch-proxy:alpine-latest` - `quay.io/vouch/vouch-proxy:alpine-x.y.z` +As of `v0.43.0` both of these images are [Multi-platform builds](https://docs.docker.com/build/building/multi-platform/) supporting `linux/amd64` and `linux/arm64`. + Vouch Proxy `arm` images are available on [Docker Hub](https://hub.docker.com/r/voucher/vouch-proxy/) - `voucher/vouch-proxy:latest-arm` From 9197e442da9bf06cd9c38584b151f8672d406640 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 14:44:09 -0700 Subject: [PATCH 715/736] #528 simplify user data cleanup --- CHANGELOG.md | 6 +++--- pkg/providers/discord/discord.go | 25 ++++++++++++++++++++----- pkg/structs/structs.go | 21 --------------------- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b2d38b..ca55b518 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,9 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. -* Implement a Discord provider that uses `Username` as the username to match against in the `whiteList` config - * Or uses `Username#Discriminator` if the Discriminator is present - * Or uses ID if `discord_use_ids` is set +- Implement a Discord provider that uses `Username` as the username to match against in the `whiteList` config + - Or uses `Username#Discriminator` if the Discriminator is present + - Or uses ID if `discord_use_ids` is set ## v0.40.0 diff --git a/pkg/providers/discord/discord.go b/pkg/providers/discord/discord.go index 82d12a73..8221d0a8 100644 --- a/pkg/providers/discord/discord.go +++ b/pkg/providers/discord/discord.go @@ -12,6 +12,7 @@ package discord import ( "encoding/json" + "fmt" "io" "net/http" @@ -58,13 +59,27 @@ func (Provider) GetUserInfo(r *http.Request, user *structs.User, customClaims *s log.Error(err) return err } - discordUser := structs.DiscordUser{} - if err = json.Unmarshal(data, &discordUser); err != nil { + dUser := structs.DiscordUser{} + if err = json.Unmarshal(data, &dUser); err != nil { log.Error(err) return err } - discordUser.PrepareUserData() - user.Username = discordUser.PreparedUsername - user.Email = discordUser.Email + + // If the provider is configured to use IDs, the ID is copied to PreparedUsername. + if cfg.GenOAuth.DiscordUseIDs { + user.Username = dUser.Id + } else { + user.Username = dUser.Username + + // If the Discriminator is present that is appended to the Username in the format "Username#Discriminator" + // to match the old format of Discord usernames + // Previous format which is being phased out: https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" + // Details about the new username requirements: https://support.discord.com/hc/en-us/articles/12620128861463 + if dUser.Discriminator != "0" { + user.Username = fmt.Sprintf("%s#%s", dUser.Username, dUser.Discriminator) + } + } + user.Email = dUser.Email + return nil } diff --git a/pkg/structs/structs.go b/pkg/structs/structs.go index 33979f94..368fb0f8 100644 --- a/pkg/structs/structs.go +++ b/pkg/structs/structs.go @@ -11,10 +11,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. package structs import ( - "fmt" "strconv" - - "github.com/vouch/vouch-proxy/pkg/cfg" ) // CustomClaims Temporary struct storing custom claims until JWT creation. @@ -257,21 +254,3 @@ type DiscordUser struct { PreparedUsername string } - -// PrepareUserData copies the Username to PreparedUsername. -// If the provider is configured to use IDs, the ID is copied to PreparedUsername. -// If the Discriminator is present that is appended to the Username in the format "Username#Discriminator" -// to match the old format of Discord usernames -// Previous format which is being phased out: https://support.discord.com/hc/en-us/articles/4407571667351-Law-Enforcement-Guidelines Subheading "How to find usernames and discriminators" -// Details about the new username requirements: https://support.discord.com/hc/en-us/articles/12620128861463 -func (u *DiscordUser) PrepareUserData() { - if cfg.GenOAuth.DiscordUseIDs { - u.PreparedUsername = u.Id - return - } - - u.PreparedUsername = u.Username - if u.Discriminator != "0" { - u.PreparedUsername = fmt.Sprintf("%s#%s", u.Username, u.Discriminator) - } -} From e0fabbf372ba95bd6d812d1a75eab1f96747476c Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 14:53:28 -0700 Subject: [PATCH 716/736] upgrade jwt package to v5 --- go.mod | 1 + go.sum | 2 ++ pkg/cfg/cfg.go | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c21e3514..f6dc13c6 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.3 github.com/gorilla/securecookie v1.1.2 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go.sum b/go.sum index 8eff9038..84eaa29a 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= +github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 7a0e98bb..b299455d 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -27,7 +27,7 @@ import ( "strings" "github.com/go-viper/mapstructure/v2" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v5" "github.com/kelseyhightower/envconfig" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" From d90bcf1ff3a51f6f5a23224724854d5334b57828 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 15:18:47 -0700 Subject: [PATCH 717/736] if discord_use_ids is set make sure discord is the provider --- pkg/cfg/oauth.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/cfg/oauth.go b/pkg/cfg/oauth.go index 51e94a3d..5b4e90b3 100644 --- a/pkg/cfg/oauth.go +++ b/pkg/cfg/oauth.go @@ -146,6 +146,8 @@ func oauthBasicTest() error { case GenOAuth.Provider != Providers.Google && GenOAuth.Provider != Providers.IndieAuth && GenOAuth.Provider != Providers.HomeAssistant && GenOAuth.Provider != Providers.ADFS && GenOAuth.Provider != Providers.Azure && GenOAuth.UserInfoURL == "": // everyone except IndieAuth, Google and ADFS has an userInfoURL, and Azure does not actively use it return errors.New("configuration error: oauth.user_info_url not found") + case GenOAuth.Provider != Providers.Discord && GenOAuth.DiscordUseIDs: + return errors.New("configuration error: discord_use_ids is true but oauth.provider is not 'discord'") case GenOAuth.CodeChallengeMethod != "" && (GenOAuth.CodeChallengeMethod != "plain" && GenOAuth.CodeChallengeMethod != "S256"): return errors.New("configuration error: oauth.code_challenge_method must be either 'S256' or 'plain'") case GenOAuth.Provider == Providers.Azure || GenOAuth.Provider == Providers.ADFS || GenOAuth.Provider == Providers.Nextcloud || GenOAuth.Provider == Providers.OIDC: From 62f9677471934e876fe0922629fc8c0ef5f8aec5 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 16:09:41 -0700 Subject: [PATCH 718/736] add URL to OAuth2 docs on discord --- config/config.yml_example_discord | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.yml_example_discord b/config/config.yml_example_discord index 6a197b45..3a251f7e 100644 --- a/config/config.yml_example_discord +++ b/config/config.yml_example_discord @@ -2,9 +2,11 @@ # Vouch Proxy configuration # bare minimum to get Vouch Proxy running with Discord as an OpenID Provider + vouch: domains: - yourdomain.com + # whiteList is a list of usernames that will allow a login if allowAllUsers is false whiteList: # The default behavior matches the Discord user's username @@ -22,6 +24,7 @@ vouch: # vouch.cookie.domain must be set when enabling allowAllUsers # domain: yourdomain.com +# https://discord.com/developers/docs/topics/oauth2 oauth: provider: discord client_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxx From 94122a185bb0f3108bbd703494491125d59dee7f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 16:15:13 -0700 Subject: [PATCH 719/736] upgrade jwt package to v5 --- go.mod | 1 - go.sum | 2 -- pkg/jwtmanager/jwtmanager.go | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/go.mod b/go.mod index f6dc13c6..f9f84100 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ toolchain go1.23.2 require ( github.com/go-viper/mapstructure/v2 v2.4.0 - github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.7.0 github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index 84eaa29a..6888725d 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index b80caae5..891e3ca3 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -21,7 +21,7 @@ import ( "strings" "time" - jwt "github.com/golang-jwt/jwt" + jwt "github.com/golang-jwt/jwt/v5" "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" From d091dc890b7884f7a8dc10ba7f794797441f41e6 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 18:11:33 -0700 Subject: [PATCH 720/736] Revert "upgrade jwt package to v5" This reverts commit 94122a185bb0f3108bbd703494491125d59dee7f. --- go.mod | 1 + go.sum | 2 ++ pkg/jwtmanager/jwtmanager.go | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f9f84100..f6dc13c6 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.23.2 require ( github.com/go-viper/mapstructure/v2 v2.4.0 + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.7.0 github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index 6888725d..84eaa29a 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 891e3ca3..b80caae5 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -21,7 +21,7 @@ import ( "strings" "time" - jwt "github.com/golang-jwt/jwt/v5" + jwt "github.com/golang-jwt/jwt" "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" From 1de0c8873cbc29b90d91a6d73ee79125cb3383f9 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 23 Jul 2025 18:12:42 -0700 Subject: [PATCH 721/736] Revert "upgrade jwt package to v5" This reverts commit e0fabbf372ba95bd6d812d1a75eab1f96747476c. --- go.mod | 1 - go.sum | 2 -- pkg/cfg/cfg.go | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/go.mod b/go.mod index f6dc13c6..c21e3514 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/golang-jwt/jwt/v5 v5.2.3 github.com/gorilla/securecookie v1.1.2 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go.sum b/go.sum index 84eaa29a..8eff9038 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,6 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= -github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index b299455d..7a0e98bb 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -27,7 +27,7 @@ import ( "strings" "github.com/go-viper/mapstructure/v2" - "github.com/golang-jwt/jwt/v5" + "github.com/golang-jwt/jwt" "github.com/kelseyhightower/envconfig" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" From 13d6a79b211f16cfc03cf182d11cb224df227d63 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 24 Jul 2025 16:16:28 -0700 Subject: [PATCH 722/736] use golang-jwt/jwt/v4 https://github.com/vouch/vouch-proxy/security/dependabot/11 --- CHANGELOG.md | 4 ++++ go.mod | 3 ++- go.sum | 4 ++-- pkg/cfg/cfg.go | 2 +- pkg/jwtmanager/jwtmanager.go | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd345f37..ba7a9ba0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.44.0 + +- migrate to github.com/golang-jwt/jwt/v4 + ## v0.43.0 - support multi-platform / multi-arch builds for published Docker images including `linux/amd64` and `linux/arm64` diff --git a/go.mod b/go.mod index c21e3514..87be9385 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ toolchain go1.23.2 require ( github.com/go-viper/mapstructure/v2 v2.4.0 - github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/go-cmp v0.7.0 github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 @@ -48,3 +47,5 @@ require ( golang.org/x/text v0.27.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +require github.com/golang-jwt/jwt/v4 v4.5.2 diff --git a/go.sum b/go.sum index 8eff9038..039b0042 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index 7a0e98bb..b239242c 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -27,7 +27,7 @@ import ( "strings" "github.com/go-viper/mapstructure/v2" - "github.com/golang-jwt/jwt" + "github.com/golang-jwt/jwt/v4" "github.com/kelseyhightower/envconfig" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index b80caae5..34425547 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -21,7 +21,7 @@ import ( "strings" "time" - jwt "github.com/golang-jwt/jwt" + jwt "github.com/golang-jwt/jwt/v4" "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" From e6494d9de45e09b66eb48cae38f6725833523725 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 24 Jul 2025 16:27:06 -0700 Subject: [PATCH 723/736] #528 support for Discord OAuth2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75ee4e7f..67642988 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Vouch Proxy supports many OAuth and OIDC login providers and can enforce authent - [Alibaba / Aliyun iDaas](https://github.com/vouch/vouch-proxy/issues/344) - [AWS Cognito](https://github.com/vouch/vouch-proxy/issues/105) - [Twitch](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_twitch) -- [Discord](https://github.com/eltariel/foundry-docker-nginx-vouch) +- [Discord](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_discord) - [SecureAuth](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_secureauth) - [Gitea](https://github.com/vouch/vouch-proxy/blob/master/config/config.yml_example_gitea) - [Keycloak](config/config.yml_example_keycloak) From eac3c88e9186d815e0e4d3f5699704ab1688fbc4 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 May 2026 10:40:20 -0700 Subject: [PATCH 724/736] upgrade to golang 1.26 --- .github/workflows/coverage.yml | 2 +- .travis.yml | 2 +- Dockerfile | 2 +- Dockerfile.alpine | 2 +- do.sh | 2 +- go.mod | 37 +++++++++++++++++----------------- go.sum | 34 +++++++++++++++++++++++++++++++ 7 files changed, 58 insertions(+), 23 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 4c9cff1a..9b185a15 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: # go: ['1.14', '1.15'] - go: ['1.23'] + go: ['1.26'] steps: - uses: actions/setup-go@v2 diff --git a/.travis.yml b/.travis.yml index a2d3709c..51378eca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ services: - docker go: - - "1.23" + - "1.26" env: - ISTRAVIS=true diff --git a/Dockerfile b/Dockerfile index 031083a9..f70533d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.23 AS builder +FROM golang:1.26 AS builder ARG UID=999 ARG GID=999 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 19f650c8..7b879a11 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ # quay.io/vouch/vouch-proxy # https://github.com/vouch/vouch-proxy -FROM golang:1.23 AS builder +FROM golang:1.26 AS builder ARG UID=999 ARG GID=999 diff --git a/do.sh b/do.sh index 2dec29f2..b1baa801 100755 --- a/do.sh +++ b/do.sh @@ -13,7 +13,7 @@ fi IMAGE=quay.io/vouch/vouch-proxy:latest ALPINE=quay.io/vouch/vouch-proxy:alpine-latest -GOIMAGE=golang:1.23 +GOIMAGE=golang:1.26 NAME=vouch-proxy HTTPPORT=9090 GODOC_PORT=5050 diff --git a/go.mod b/go.mod index 87be9385..49ac6ce2 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/vouch/vouch-proxy -go 1.23.0 +go 1.25.0 -toolchain go1.23.2 +toolchain go1.26.2 require ( - github.com/go-viper/mapstructure/v2 v2.4.0 + github.com/go-viper/mapstructure/v2 v2.5.0 github.com/google/go-cmp v0.7.0 github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 @@ -13,38 +13,39 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/spf13/viper v1.20.1 - github.com/stretchr/testify v1.10.0 + github.com/spf13/viper v1.21.0 + github.com/stretchr/testify v1.11.1 github.com/theckman/go-securerandom v0.1.1 github.com/tsenart/vegeta v12.7.0+incompatible - go.uber.org/zap v1.27.0 - golang.org/x/net v0.42.0 - golang.org/x/oauth2 v0.30.0 + go.uber.org/zap v1.28.0 + golang.org/x/net v0.53.0 + golang.org/x/oauth2 v0.36.0 ) require ( - cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.3.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect - github.com/spf13/cast v1.9.2 // indirect - github.com/spf13/pflag v1.0.7 // indirect + github.com/sagikazarmark/locafero v0.12.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 039b0042..ce7cc164 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -10,8 +12,12 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -45,26 +51,42 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= +github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= +github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= @@ -77,17 +99,29 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= From 627598afee3fce58f78a9baf6799d2f65e0caa68 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 May 2026 10:43:01 -0700 Subject: [PATCH 725/736] upgrade to golang 1.26 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e15161..68c96738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.46.0 + +- upgrade golang to `v1.26` from `v1.23` + ## v0.45.0 - Implement a Discord provider that uses `Username` as the username to match against in the `whiteList` config From 3c3bfc820da3b048f8579c0956ce37ec04d61212 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 May 2026 11:16:24 -0700 Subject: [PATCH 726/736] upgrade to golang 1.26 --- go.mod | 2 +- go.sum | 34 ---------------------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 49ac6ce2..bda5fcf8 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,6 @@ require ( github.com/pelletier/go-toml/v2 v2.3.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect - github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect @@ -46,6 +45,7 @@ require ( golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.36.0 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index ce7cc164..8f3e5483 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= @@ -10,12 +8,8 @@ github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfx github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= @@ -49,42 +43,24 @@ github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= -github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 h1:7z3LSn867ex6VSaahyKadf4WtSsJIgne6A1WLOAGM8A= github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -97,8 +73,6 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -106,20 +80,12 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 8884803a88166611aeab93525747713b84daef8f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 May 2026 19:07:45 -0700 Subject: [PATCH 727/736] fix host check against jwtaudience claim upgrade to upgrade to github.com/golang-jwt/jwt/v5 --- go.mod | 3 +- go.sum | 4 +-- handlers/handlers_test.go | 10 +++---- handlers/validate.go | 6 ++-- pkg/cfg/cfg.go | 2 +- pkg/jwtmanager/jwtcache.go | 5 ++-- pkg/jwtmanager/jwtcache_test.go | 6 ++-- pkg/jwtmanager/jwtmanager.go | 31 ++++++++++---------- pkg/jwtmanager/jwtmanager_test.go | 48 +++++++++++++++++++++++++++---- 9 files changed, 76 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index bda5fcf8..6c8ac1b3 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.26.2 require ( github.com/go-viper/mapstructure/v2 v2.5.0 + github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/go-cmp v0.7.0 github.com/gorilla/sessions v1.4.0 github.com/julienschmidt/httprouter v1.3.0 @@ -48,5 +49,3 @@ require ( gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -require github.com/golang-jwt/jwt/v4 v4.5.2 diff --git a/go.sum b/go.sum index 8f3e5483..1c68e034 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx5 github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index 3cd91598..2ec3101e 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -139,11 +139,11 @@ func init() { // log.SetLevel(log.DebugLevel) lc = jwtmanager.VouchClaims{ - Username: u1.Username, - CustomClaims: customClaims.Claims, - PAccessToken: t1.PAccessToken, - PIdToken: t1.PIdToken, - StandardClaims: jwtmanager.StandardClaims, + Username: u1.Username, + CustomClaims: customClaims.Claims, + PAccessToken: t1.PAccessToken, + PIdToken: t1.PIdToken, + RegisteredClaims: jwtmanager.RegisteredClaims, } json.Unmarshal([]byte(claimjson), &customClaims.Claims) } diff --git a/handlers/validate.go b/handlers/validate.go index bc01bf32..8d225dd8 100644 --- a/handlers/validate.go +++ b/handlers/validate.go @@ -20,6 +20,7 @@ import ( "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" + "github.com/vouch/vouch-proxy/pkg/domains" "github.com/vouch/vouch-proxy/pkg/jwtmanager" "github.com/vouch/vouch-proxy/pkg/responses" ) @@ -51,7 +52,7 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { } if !cfg.Cfg.AllowAllUsers { - if !claims.SiteInAudience(r.Host) { + if !claims.SiteInAudience(r.Host) || domains.Matches(r.Host) == "" { send401or200PublicAccess(w, r, fmt.Errorf("http header 'Host: %s' not authorized for configured `vouch.domains` (is Host being sent properly?)", r.Host)) return @@ -82,9 +83,6 @@ func ValidateRequestHandler(w http.ResponseWriter, r *http.Request) { responses.OK200(w, r) } - // TODO - // parse the jwt and see if the claim is valid for the domain - } func generateCustomClaimsHeaders(w http.ResponseWriter, claims *jwtmanager.VouchClaims) { diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index b239242c..b299455d 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -27,7 +27,7 @@ import ( "strings" "github.com/go-viper/mapstructure/v2" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/kelseyhightower/envconfig" "github.com/spf13/viper" securerandom "github.com/theckman/go-securerandom" diff --git a/pkg/jwtmanager/jwtcache.go b/pkg/jwtmanager/jwtcache.go index 9b07462d..b12ab188 100644 --- a/pkg/jwtmanager/jwtcache.go +++ b/pkg/jwtmanager/jwtcache.go @@ -103,8 +103,9 @@ func getCacheExpirationDuration(claims *VouchClaims) time.Duration { now := time.Now().Unix() expiresAt := now + int64(dExp/time.Second) - if !claims.VerifyExpiresAt(expiresAt, true) { - jwtExpiresIn := time.Duration((claims.ExpiresAt - now) * int64(time.Second)) + + if claims.ExpiresAt.Unix() < expiresAt { + jwtExpiresIn := time.Duration((claims.ExpiresAt.Unix() - now) * int64(time.Second)) log.Debugf("cache default expiration (%d) is after jwt expiration (%d). setting cache expiration to claim expiration for this entry", dExp, jwtExpiresIn) return jwtExpiresIn } diff --git a/pkg/jwtmanager/jwtcache_test.go b/pkg/jwtmanager/jwtcache_test.go index 3f57559e..fe5ed945 100644 --- a/pkg/jwtmanager/jwtcache_test.go +++ b/pkg/jwtmanager/jwtcache_test.go @@ -15,6 +15,8 @@ import ( "reflect" "testing" "time" + + "github.com/golang-jwt/jwt/v5" ) func Test_getCacheExpirationDuration(t *testing.T) { @@ -23,11 +25,11 @@ func Test_getCacheExpirationDuration(t *testing.T) { now := time.Now() claimsA := lc - claimsA.ExpiresAt = now.Add(time.Minute * time.Duration(expire+5)).Unix() + claimsA.ExpiresAt = jwt.NewNumericDate(now.Add(time.Minute * time.Duration(expire+5))) claimsB := lc dBexp := time.Minute * time.Duration(expire-5) - claimsB.ExpiresAt = now.Add(dBexp).Unix() + claimsB.ExpiresAt = jwt.NewNumericDate(now.Add(dBexp)) tests := []struct { name string diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 34425547..49cde754 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -21,7 +21,7 @@ import ( "strings" "time" - jwt "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v5" "go.uber.org/zap" "github.com/vouch/vouch-proxy/pkg/cfg" @@ -37,15 +37,15 @@ type VouchClaims struct { CustomClaims map[string]interface{} PAccessToken string PIdToken string - jwt.StandardClaims + jwt.RegisteredClaims } -// StandardClaims jwt.StandardClaims implementation -var StandardClaims jwt.StandardClaims +// RegisteredClaims jwt.RegisteredClaims implementation +var RegisteredClaims jwt.RegisteredClaims var logger *zap.Logger var log *zap.SugaredLogger -var aud string +var aud []string // Configure see main.go configure() func Configure() { @@ -53,14 +53,14 @@ func Configure() { logger = cfg.Logging.FastLogger cacheConfigure() aud = audience() - StandardClaims = jwt.StandardClaims{ + RegisteredClaims = jwt.RegisteredClaims{ Issuer: cfg.Cfg.JWT.Issuer, Audience: aud, } } // `aud` of the issued JWT https://tools.ietf.org/html/rfc7519#section-4.1.3 -func audience() string { +func audience() []string { aud := make([]string, 0) // TODO: the Sites that end up in the JWT come from here // if we add fine grain ability (ACL?) to the equation @@ -71,7 +71,7 @@ func audience() string { if cfg.Cfg.Cookie.Domain != "" { aud = append(aud, cfg.Cfg.Cookie.Domain) } - return strings.Join(aud, comma) + return aud } // NewVPJWT issue a signed Vouch Proxy JWT for a user @@ -83,11 +83,11 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs customClaims.Claims, ptokens.PAccessToken, ptokens.PIdToken, - StandardClaims, + RegisteredClaims, } claims.Audience = aud - claims.ExpiresAt = time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge)).Unix() + claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Minute * time.Duration(cfg.Cfg.JWT.MaxAge))) // https://github.com/vouch/vouch-proxy/issues/287 if cfg.Cfg.Headers.AccessToken == "" { @@ -101,7 +101,7 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs // https://godoc.org/github.com/golang-jwt/jwt#NewWithClaims token := jwt.NewWithClaims(jwt.GetSigningMethod(cfg.Cfg.JWT.SigningMethod), claims) // log.Debugf("token: %v", token) - log.Debugf("token created, expires: %d diff from now: %d", claims.StandardClaims.ExpiresAt, claims.StandardClaims.ExpiresAt-time.Now().Unix()) + log.Debugf("token created, expires: %d diff from now: %d", claims.RegisteredClaims.ExpiresAt, claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()) key, err := cfg.SigningKey() if err != nil { @@ -121,6 +121,7 @@ func NewVPJWT(u structs.User, customClaims structs.CustomClaims, ptokens structs return ss, nil } +// TODO: is this dead code? // SiteInToken searches does the token contain the site? func SiteInToken(site string, token *jwt.Token) bool { if claims, ok := token.Claims.(*VouchClaims); ok { @@ -158,10 +159,10 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { } // SiteInAudience does the claim contain the value? -func (claims *VouchClaims) SiteInAudience(site string) bool { - for _, s := range strings.Split(aud, comma) { - if strings.Contains(site, s) { - log.Debugf("site %s is found for claims.Audience %s", site, s) +func (claims *VouchClaims) SiteInAudience(s string) bool { + for _, a := range claims.Audience { + if s == a || strings.HasSuffix(s, "."+a) { + log.Debugf("site %s is found for claims.Audience %s", s, a) return true } } diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index 8be3e6a1..8d4ca455 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -53,18 +53,22 @@ func init() { customClaims.Claims, t1.PAccessToken, t1.PIdToken, - StandardClaims, + RegisteredClaims, } +} +func setUp(t *testing.T, cfgFile string) { + rootDir := os.Getenv(cfg.Branding.UCName + "_ROOT") + if err := os.Setenv(cfg.Branding.UCName+"_CONFIG", filepath.Join(rootDir, "config/testing", cfgFile)); err != nil { + t.Errorf("failed setting environment variable %s_CONFIG", cfg.Branding.UCName) + } + Configure() + cfg.InitForTestPurposes() } func TestClaimsHMAC(t *testing.T) { - rootDir := os.Getenv(cfg.Branding.UCName + "_ROOT") for _, cfgFile := range []string{"test_config.yml", "test_config_rsa.yml"} { - if err := os.Setenv(cfg.Branding.UCName+"_CONFIG", filepath.Join(rootDir, "config/testing", cfgFile)); err != nil { - t.Errorf("failed setting environment variable %s_CONFIG", cfg.Branding.UCName) - } - + setUp(t, cfgFile) json.Unmarshal([]byte(claimjson), &customClaims.Claims) log.Debugf("jwt config %s %d", string(cfg.Cfg.JWT.Secret), cfg.Cfg.JWT.MaxAge) @@ -85,6 +89,7 @@ func TestClaimsHMAC(t *testing.T) { } func TestClaims(t *testing.T) { + setUp(t, "test_config.yml") aud = audience() log.Debugf("jwt config %s %d", string(cfg.Cfg.JWT.Secret), cfg.Cfg.JWT.MaxAge) assert.NotEmpty(t, cfg.Cfg.JWT.Secret) @@ -102,3 +107,34 @@ func TestClaims(t *testing.T) { log.Infof("Audience: %+v", aud) assert.True(t, SiteInToken(cfg.Cfg.Domains[0], utsParsed)) } + +func TestVouchClaims_SiteInAudience(t *testing.T) { + tests := []struct { + name string // description of this test case + cfgFile string + s string + want bool + }{ + // test cases + {"vouch.github.io", "test_config_oauth_claims.yml", "vouch.github.io", true}, + {"evilvouch.github.io", "test_config_oauth_claims.yml", "evilvouch.github.io", false}, + {"vouch.github.io.attacker.com", "test_config_oauth_claims.yml", "vouch.github.io.attacker.com", false}, + {"evilvouch.github.io.attacker.com", "test_config_oauth_claims.yml", "evilvouch.github.io.attacker.com", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setUp(t, tt.cfgFile) + jwt, err := NewVPJWT(u1, customClaims, t1) + assert.NoError(t, err) + claims, err := ClaimsFromJWT(jwt) + if err != nil { + t.Fatalf("could not construct receiver type: %v", err) + } + got := claims.SiteInAudience(tt.s) + // TODO: update the condition below to compare got with tt.want. + if got != tt.want { + t.Errorf("SiteInAudience() = %v, want %v", got, tt.want) + } + }) + } +} From ad0b75c1c6fa99537c103d6b33fa61d52b3c72a1 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 7 May 2026 19:08:57 -0700 Subject: [PATCH 728/736] v0.47.0 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68c96738..b9f50edf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.47.0 + +- improve host check against jwt audience claim +- upgrade to github.com/golang-jwt/jwt/v5 + ## v0.46.0 - upgrade golang to `v1.26` from `v1.23` From 60e29beb7f9cf47b92c776a5ab2acfd1fb61484b Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Fri, 8 May 2026 08:20:20 -0700 Subject: [PATCH 729/736] set Expires element for proper cookie deletion --- CHANGELOG.md | 4 ++++ pkg/cookie/cookie.go | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f50edf..7af23fcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.47.1 + +- set Cookie.Expires to Jan 1 1970 to delete the VP cookie in a manner most browsers will comply with + ## v0.47.0 - improve host check against jwt audience claim diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index 75354dd2..aa5b14ac 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -16,6 +16,7 @@ import ( "net/http" "strconv" "strings" + "time" "unicode/utf8" // "github.com/vouch/vouch-proxy/pkg/structs" @@ -162,11 +163,12 @@ func ClearCookie(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(cookie.Name, cfg.Cfg.Cookie.Name) { log.Debugf("deleting cookie: %s", cookie.Name) http.SetCookie(w, &http.Cookie{ - Name: cookie.Name, - Value: "delete", - Path: "/", - Domain: domain, - MaxAge: -1, + Name: cookie.Name, + Value: "delete", + Path: "/", + Domain: domain, + // https://stackoverflow.com/questions/5285940/correct-way-to-delete-cookies-server-side + Expires: time.Unix(0, 0), // system dependent but usually Thu, 01 Jan 1970 00:00:00 GMT Secure: cfg.Cfg.Cookie.Secure, HttpOnly: cfg.Cfg.Cookie.HTTPOnly, }) From d46c6e0ba1a3385c2e042d8f04c4c64b11a60363 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Courteau Date: Mon, 11 May 2026 21:45:58 -0400 Subject: [PATCH 730/736] fix SiteInAudience for legacy comma-separated audience claims The jwt/v4 to jwt/v5 migration changed the audience type from string to []string. Old JWTs serialized multiple domains as a single comma-joined string ("a.com,b.com"). When jwt/v5 parses these, it produces a one-element []string containing the full comma-separated value, so SiteInAudience fails to match any individual domain. This splits each audience element on commas before matching, which recovers the original per-domain values. For JWTs issued after the migration (audience already a proper array), the split is a no-op. Also adds a subdomain test case to the existing SiteInAudience tests and a dedicated test for the legacy comma-separated format, covering exact match, subdomain match, and suffix attack prevention. Fixes vouch/vouch-proxy#608 --- pkg/jwtmanager/jwtmanager.go | 10 ++++-- pkg/jwtmanager/jwtmanager_test.go | 51 +++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 49cde754..25545f89 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -161,9 +161,13 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { // SiteInAudience does the claim contain the value? func (claims *VouchClaims) SiteInAudience(s string) bool { for _, a := range claims.Audience { - if s == a || strings.HasSuffix(s, "."+a) { - log.Debugf("site %s is found for claims.Audience %s", s, a) - return true + // jwt/v4 serialized the audience as a comma-separated string; + // jwt/v5 deserializes that into a single-element []string. + for _, d := range strings.Split(a, comma) { + if s == d || strings.HasSuffix(s, "."+d) { + log.Debugf("site %s is found for claims.Audience %s", s, d) + return true + } } } return false diff --git a/pkg/jwtmanager/jwtmanager_test.go b/pkg/jwtmanager/jwtmanager_test.go index 8d4ca455..654723a1 100644 --- a/pkg/jwtmanager/jwtmanager_test.go +++ b/pkg/jwtmanager/jwtmanager_test.go @@ -16,10 +16,11 @@ import ( "path/filepath" "testing" + jwt "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" + "github.com/vouch/vouch-proxy/pkg/cfg" "github.com/vouch/vouch-proxy/pkg/structs" - - "github.com/stretchr/testify/assert" ) var ( @@ -110,16 +111,16 @@ func TestClaims(t *testing.T) { func TestVouchClaims_SiteInAudience(t *testing.T) { tests := []struct { - name string // description of this test case + name string cfgFile string s string want bool }{ - // test cases - {"vouch.github.io", "test_config_oauth_claims.yml", "vouch.github.io", true}, - {"evilvouch.github.io", "test_config_oauth_claims.yml", "evilvouch.github.io", false}, - {"vouch.github.io.attacker.com", "test_config_oauth_claims.yml", "vouch.github.io.attacker.com", false}, - {"evilvouch.github.io.attacker.com", "test_config_oauth_claims.yml", "evilvouch.github.io.attacker.com", false}, + {"exact match", "test_config_oauth_claims.yml", "vouch.github.io", true}, + {"subdomain match", "test_config_oauth_claims.yml", "sub.vouch.github.io", true}, + {"suffix attack", "test_config_oauth_claims.yml", "evilvouch.github.io", false}, + {"attacker parent domain", "test_config_oauth_claims.yml", "vouch.github.io.attacker.com", false}, + {"attacker combined", "test_config_oauth_claims.yml", "evilvouch.github.io.attacker.com", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -131,9 +132,39 @@ func TestVouchClaims_SiteInAudience(t *testing.T) { t.Fatalf("could not construct receiver type: %v", err) } got := claims.SiteInAudience(tt.s) - // TODO: update the condition below to compare got with tt.want. if got != tt.want { - t.Errorf("SiteInAudience() = %v, want %v", got, tt.want) + t.Errorf("SiteInAudience(%q) = %v, want %v", tt.s, got, tt.want) + } + }) + } +} + +func TestSiteInAudienceLegacyFormat(t *testing.T) { + claims := &VouchClaims{ + RegisteredClaims: jwt.RegisteredClaims{ + Audience: jwt.ClaimStrings{"vouch.github.io,other.test"}, + }, + } + + tests := []struct { + name string + s string + want bool + }{ + {"exact first", "vouch.github.io", true}, + {"exact second", "other.test", true}, + {"subdomain first", "sub.vouch.github.io", true}, + {"subdomain second", "sub.other.test", true}, + {"suffix attack first", "evilvouch.github.io", false}, + {"suffix attack second", "evilother.test", false}, + {"attacker parent", "vouch.github.io.attacker.com", false}, + {"unrelated", "evil.com", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := claims.SiteInAudience(tt.s) + if got != tt.want { + t.Errorf("SiteInAudience(%q) = %v, want %v", tt.s, got, tt.want) } }) } From 622ddecf0109767eb4698795b50ad0a42d8bb490 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 13 May 2026 02:14:46 -0700 Subject: [PATCH 731/736] minor logging improvements --- handlers/login.go | 2 +- pkg/cookie/cookie.go | 2 +- pkg/jwtmanager/jwtmanager.go | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/handlers/login.go b/handlers/login.go index 66c041e3..34f26f58 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -259,7 +259,7 @@ func oauthLoginURL(r *http.Request, session sessions.Session) string { if len(cfg.GenOAuth.RedirectURLs) > 0 { found := false domain := domains.Matches(r.Host) - log.Debugf("/login looking for callback_url matching %s", domain) + log.Debugf("/login looking for callback_url matching %s from host %s", domain, r.Host) for _, v := range cfg.GenOAuth.RedirectURLs { if strings.Contains(v, domain) { found = true diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index aa5b14ac..26dc845c 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -48,8 +48,8 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { // Allow overriding the cookie domain in the config file if cfg.Cfg.Cookie.Domain != "" { domain = cfg.Cfg.Cookie.Domain - log.Debugf("setting the cookie domain to %v", domain) } + log.Debugf("setting the cookie domain to %v", domain) cookie := http.Cookie{ Name: cfg.Cfg.Cookie.Name, diff --git a/pkg/jwtmanager/jwtmanager.go b/pkg/jwtmanager/jwtmanager.go index 49cde754..b68a7db6 100644 --- a/pkg/jwtmanager/jwtmanager.go +++ b/pkg/jwtmanager/jwtmanager.go @@ -160,7 +160,9 @@ func ParseTokenString(tokenString string) (*jwt.Token, error) { // SiteInAudience does the claim contain the value? func (claims *VouchClaims) SiteInAudience(s string) bool { + log.Debugf("claims.Audience: %+v", claims.Audience) for _, a := range claims.Audience { + log.Debugf("evaluating audience %s vs site %s", a, s) if s == a || strings.HasSuffix(s, "."+a) { log.Debugf("site %s is found for claims.Audience %s", s, a) return true From b683f602d91d4958b204cb0df5e45433c075e8be Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Wed, 13 May 2026 02:25:12 -0700 Subject: [PATCH 732/736] - fix [#608](https://github.com/vouch/vouch-proxy/issues/608) accomodating golang-jwt/jwt/v5 audience string format - HT @macourteau --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7af23fcd..e7aae004 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.47.2 + +- fix [#608](https://github.com/vouch/vouch-proxy/issues/608) accomodating golang-jwt/jwt/v5 audience string format - HT @macourteau + ## v0.47.1 - set Cookie.Expires to Jan 1 1970 to delete the VP cookie in a manner most browsers will comply with From fa18ce30ba50a4863a436acad044c22965329c4f Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 4 Jun 2026 13:51:15 -0700 Subject: [PATCH 733/736] multi part cookie check improvements set a limit for the number of cookie parts and test the limit before instantiating the array --- pkg/cookie/cookie.go | 43 ++++++++++--------------- pkg/cookie/cookie_test.go | 68 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/pkg/cookie/cookie.go b/pkg/cookie/cookie.go index 26dc845c..4f8d2de9 100644 --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ -26,6 +26,7 @@ import ( ) const maxCookieSize = 4000 +const maxCookieParts = 32 var log *zap.SugaredLogger var sameSite http.SameSite @@ -42,7 +43,6 @@ func SetCookie(w http.ResponseWriter, r *http.Request, val string) { } func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { - cookieName := cfg.Cfg.Cookie.Name // foreach domain domain := domains.Matches(r.Host) // Allow overriding the cookie domain in the config file @@ -51,6 +51,7 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { } log.Debugf("setting the cookie domain to %v", domain) + // create the cookie and then test to see if it's too big cookie := http.Cookie{ Name: cfg.Cfg.Cookie.Name, Value: val, @@ -62,54 +63,38 @@ func setCookie(w http.ResponseWriter, r *http.Request, val string, maxAge int) { SameSite: sameSite, } cookieSize := len(cookie.String()) - cookie.Value = "" - emptyCookieSize := len(cookie.String()) // Cookies have a max size of 4096 bytes, but to support most browsers, we should stay below 4000 bytes // https://tools.ietf.org/html/rfc6265#section-6.1 // http://browsercookielimits.squawky.net/ if cookieSize > maxCookieSize { // https://www.lifewire.com/cookie-limit-per-domain-3466809 log.Warnf("cookie size: %d. cookie sizes over ~4093 bytes(depending on the browser and platform) have shown to cause issues or simply aren't supported.", cookieSize) + emptyCookie := cookie + emptyCookie.Value = "" + emptyCookieSize := len(emptyCookie.String()) cookieParts := splitCookie(val, maxCookieSize-emptyCookieSize) for i, cookiePart := range cookieParts { // Cookies are named 1of3, 2of3, 3of3 - cookieName = fmt.Sprintf("%s_%dof%d", cfg.Cfg.Cookie.Name, i+1, len(cookieParts)) - http.SetCookie(w, &http.Cookie{ - Name: cookieName, - Value: cookiePart, - Path: "/", - Domain: domain, - MaxAge: maxAge, - Secure: cfg.Cfg.Cookie.Secure, - HttpOnly: cfg.Cfg.Cookie.HTTPOnly, - SameSite: sameSite, - }) + cookie.Name = fmt.Sprintf("%s_%dof%d", cfg.Cfg.Cookie.Name, i+1, len(cookieParts)) + cookie.Value = cookiePart + http.SetCookie(w, &cookie) } } else { - http.SetCookie(w, &http.Cookie{ - Name: cookieName, - Value: val, - Path: "/", - Domain: domain, - MaxAge: maxAge, - Secure: cfg.Cfg.Cookie.Secure, - HttpOnly: cfg.Cfg.Cookie.HTTPOnly, - SameSite: sameSite, - }) + http.SetCookie(w, &cookie) } } // Cookie get the vouch jwt cookie func Cookie(r *http.Request) (string, error) { - cookieParts := make([]string, 0) + var cookieParts []string var numParts = -1 var err error cookies := r.Cookies() // Get the remaining parts // search for cookie parts in order - // this is the hotpath so we're trying to only walk once + // this is the hot path so we're trying to only walk once for _, cookie := range cookies { if cookie.Name == cfg.Cfg.Cookie.Name { return cookie.Value, nil @@ -126,6 +111,9 @@ func Cookie(r *http.Request) (string, error) { if numParts, err = strconv.Atoi(xyArray[1]); err != nil { return "", fmt.Errorf("multipart cookie fail: %s", err) } + if numParts < 1 || numParts > maxCookieParts { + return "", fmt.Errorf("multipart cookie fail: invalid part count %s", xOFy) + } log.Debugf("make cookieParts of size %d", numParts) cookieParts = make([]string, numParts) } @@ -133,6 +121,9 @@ func Cookie(r *http.Request) (string, error) { if i, err = strconv.Atoi(xyArray[0]); err != nil { return "", fmt.Errorf("multipart cookie fail: %s", err) } + if i > numParts { + return "", fmt.Errorf("multipart cookie fail: invalid part count %s", xOFy) + } cookieParts[i-1] = cookie.Value } diff --git a/pkg/cookie/cookie_test.go b/pkg/cookie/cookie_test.go index f162f0e5..928f8b80 100644 --- a/pkg/cookie/cookie_test.go +++ b/pkg/cookie/cookie_test.go @@ -45,7 +45,7 @@ func TestSplitCookie(t *testing.T) { } } -func TestCookie(t *testing.T) { +func TestCookieOld(t *testing.T) { cfg.Cfg.Cookie.Name = "_alpha_beta" ckValue1 := "charlie" ckValue2 := "delta" @@ -67,3 +67,69 @@ func TestCookie(t *testing.T) { t.Errorf("expected \"%s\" received \"%s\"", expectedValue, s) } } + +func TestCookie(t *testing.T) { + cfg.Cfg.Cookie.Name = "_alpha_beta" + ckValue1 := "charlie" + ckValue2 := "delta" + expectedValue := fmt.Sprintf("%s%s", ckValue1, ckValue2) + + r1 := &http.Request{ + Header: map[string][]string{ + "Cookie": { + fmt.Sprintf("%s_1of2=%s", cfg.Cfg.Cookie.Name, ckValue1), + fmt.Sprintf("%s_2of2=%s", cfg.Cfg.Cookie.Name, ckValue2), + }, + }, + } + + r2TooBigCookieHeader := map[string][]string{} + parts := maxCookieParts + 1 + for i := 1; i < parts; i++ { + r2TooBigCookieHeader["Cookie"] = append(r2TooBigCookieHeader["Cookie"], fmt.Sprintf("%s_%dof%d=%d", cfg.Cfg.Cookie.Name, i, parts, i)) + } + r2 := &http.Request{ + Header: r2TooBigCookieHeader, + } + + r3 := &http.Request{ + Header: map[string][]string{"Cookie": {fmt.Sprintf("%s_1of100000000000=%s", cfg.Cfg.Cookie.Name, ckValue1)}}, + } + + r4 := &http.Request{ + Header: map[string][]string{"Cookie": {fmt.Sprintf("%s_100000000000000of32=%s", cfg.Cfg.Cookie.Name, ckValue1)}}, + } + + tests := []struct { + name string // description of this test case + r *http.Request + want string + wantErr bool + }{ + {"_alpha_beta", r1, expectedValue, false}, + {"too many parts", r2, "very big", true}, + {"just one but it claims to be big", r3, "very very big", true}, + {"just one but it has a big X in XofY", r4, "very very big", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // prepare the test by rendering the cookies into the response object + tt.r.Cookies() + + got, gotErr := Cookie(tt.r) + if gotErr != nil { + if !tt.wantErr { + t.Errorf("Cookie() failed: %v", gotErr) + } + return + } + if tt.wantErr { + t.Fatal("Cookie() succeeded unexpectedly") + } + // should match + if got != tt.want { + t.Errorf("Cookie() = %v, want %v", got, tt.want) + } + }) + } +} From 5a4ec4a2c4a62a41e99352ec758ff10172adcf6e Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 4 Jun 2026 13:51:47 -0700 Subject: [PATCH 734/736] remove redundant test --- pkg/cookie/cookie_test.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/pkg/cookie/cookie_test.go b/pkg/cookie/cookie_test.go index 928f8b80..67ffe2d1 100644 --- a/pkg/cookie/cookie_test.go +++ b/pkg/cookie/cookie_test.go @@ -45,29 +45,6 @@ func TestSplitCookie(t *testing.T) { } } -func TestCookieOld(t *testing.T) { - cfg.Cfg.Cookie.Name = "_alpha_beta" - ckValue1 := "charlie" - ckValue2 := "delta" - expectedValue := fmt.Sprintf("%s%s", ckValue1, ckValue2) - r := &http.Request{ - Header: map[string][]string{ - "Cookie": { - fmt.Sprintf("%s_1of2=%s", cfg.Cfg.Cookie.Name, ckValue1), - fmt.Sprintf("%s_2of2=%s", cfg.Cfg.Cookie.Name, ckValue2), - }, - }, - } - r.Cookies() - s, err := Cookie(r) - if err != nil { - t.Error(err) - } - if expectedValue != s { - t.Errorf("expected \"%s\" received \"%s\"", expectedValue, s) - } -} - func TestCookie(t *testing.T) { cfg.Cfg.Cookie.Name = "_alpha_beta" ckValue1 := "charlie" From 62eadec50dd1d8602a355edf2fc991b5e1e318d7 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 4 Jun 2026 13:56:19 -0700 Subject: [PATCH 735/736] v0.48.0 - multipart cookie numparts check --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7aae004..f27bf2c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. +## v0.48.0 + +- improve checks of the number of parts of multipart cookies + ## v0.47.2 - fix [#608](https://github.com/vouch/vouch-proxy/issues/608) accomodating golang-jwt/jwt/v5 audience string format - HT @macourteau From 2f720ec2cce3a825b6261d941b4149b77f2a5592 Mon Sep 17 00:00:00 2001 From: Benjamin Foote Date: Thu, 11 Jun 2026 12:04:26 -0700 Subject: [PATCH 736/736] add Security Advisory context to v0.48.0 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f27bf2c9..82f4f36c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,11 @@ Coming soon! Please document any work in progress here as part of your PR. It will be moved to the next tag when released. -## v0.48.0 +## v0.48.0 SECURITY UPDATE -- improve checks of the number of parts of multipart cookies +- fixes [Unbounded Multipart Cookie Allocation DoS in vouch-proxy](https://github.com/vouch/vouch-proxy/security/advisories/GHSA-qqff-5854-px68) + - improve checks of the number of parts of multipart cookies + - set limit of number of cookie parts ## v0.47.2