From ee1b01e552ec0729932233debc690f205e294805 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Thu, 24 Oct 2019 15:28:05 +0300 Subject: [PATCH 001/251] Add the `AUTHONE_AUTH_WEB_FORM_SDK_URL` param for defined url to JS auth SDK --- .helm/values.yaml | 1 + README.md | 1 + pkg/api/change_password.go | 6 ++-- pkg/api/oauth2.go | 40 +++++++++++++++------------ pkg/config/config.go | 9 +++--- pkg/manager/change_password.go | 5 +++- pkg/manager/change_password_test.go | 2 +- pkg/manager/oauth2.go | 4 ++- pkg/manager/oauth2_test.go | 2 +- public/templates/change_password.html | 2 +- public/templates/login_form.html | 25 ----------------- public/templates/oauth_callback.html | 2 +- public/templates/oauth_login.html | 2 +- public/templates/oauth_logout.html | 2 +- 14 files changed, 47 insertions(+), 56 deletions(-) delete mode 100644 public/templates/login_form.html diff --git a/.helm/values.yaml b/.helm/values.yaml index dfdd178..dd77c19 100644 --- a/.helm/values.yaml +++ b/.helm/values.yaml @@ -57,6 +57,7 @@ backend: - AUTHONE_MAILER_FROM - AUTHONE_MAILER_SKIP_VERIFY - AUTHONE_MIGRATION_DIRECT + - AUTHONE_AUTH_WEB_FORM_SDK_URL hydra: env: diff --git a/README.md b/README.md index 2e00d12..f8d3aec 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ To start the application, you can use the following configuration parameters in | AUTHONE_MAILER_FROM | | From value. Here is no default value, it may be provided. | | AUTHONE_MAILER_SKIP_VERIFY | true | Skip validate TLS on mail server connection. | | AUTHONE_MIGRATION_DIRECT | | Used to migrate a database. If not specified, no migration is used. Acceptable values of up and down. | +| AUTHONE_AUTH_WEB_FORM_SDK_URL | | URL to the java-script file with SDK authorization. | ***Attention!*** Do not forget that ORY Hydra provides its configuration parameters that also need to be configured. For more information on this, see the project website - https://github.com/ory/hydra. diff --git a/pkg/api/change_password.go b/pkg/api/change_password.go index 29a85f3..3520c72 100644 --- a/pkg/api/change_password.go +++ b/pkg/api/change_password.go @@ -14,7 +14,7 @@ func InitChangePassword(cfg *Server) error { g := cfg.Echo.Group("/dbconnections", func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { db := c.Get("database").(database.MgoSession) - c.Set("password_manager", manager.NewChangePasswordManager(db, cfg.Registry)) + c.Set("password_manager", manager.NewChangePasswordManager(db, cfg.Registry, cfg.ServerConfig)) return next(c) } @@ -89,6 +89,7 @@ func changePasswordVerify(ctx echo.Context) error { func changePasswordForm(ctx echo.Context) error { form := new(models.ChangePasswordForm) + m := ctx.Get("password_manager").(*manager.ChangePasswordManager) if err := ctx.Bind(form); err != nil { ctx.Error(err) @@ -101,6 +102,7 @@ func changePasswordForm(ctx echo.Context) error { } return ctx.Render(http.StatusOK, "change_password.html", map[string]interface{}{ - "ClientID": form.ClientID, + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + "ClientID": form.ClientID, }) } diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index affdf4e..49b410c 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -14,7 +14,7 @@ func InitOauth2(cfg *Server) error { g := cfg.Echo.Group("/oauth2", func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { db := c.Get("database").(database.MgoSession) - c.Set("oauth_manager", manager.NewOauthManager(db, cfg.Registry, cfg.SessionConfig, cfg.HydraConfig)) + c.Set("oauth_manager", manager.NewOauthManager(db, cfg.Registry, cfg.SessionConfig, cfg.HydraConfig, cfg.ServerConfig)) return next(c) } @@ -65,11 +65,12 @@ func oauthLogin(ctx echo.Context) error { } return ctx.Render(http.StatusOK, "oauth_login.html", map[string]interface{}{ - "AuthDomain": ctx.Scheme() + "://" + ctx.Request().Host, - "Challenge": form.Challenge, - "ClientID": appID, - "PreviousLogin": previousLogin, - "SocProviders": socProviders, + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + "AuthDomain": ctx.Scheme() + "://" + ctx.Request().Host, + "Challenge": form.Challenge, + "ClientID": appID, + "PreviousLogin": previousLogin, + "SocProviders": socProviders, }) } @@ -123,8 +124,9 @@ func oauthConsent(ctx echo.Context) error { } return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ - "Challenge": form.Challenge, - "Scopes": scopes, + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + "Challenge": form.Challenge, + "Scopes": scopes, }) } @@ -145,9 +147,10 @@ func oauthConsentSubmit(ctx echo.Context) error { if err != nil { scopes, _ := m.GetScopes() return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ - "Challenge": form.Challenge, - "Scope": scopes, - "Error": err.Error(), + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + "Challenge": form.Challenge, + "Scope": scopes, + "Error": err.Error(), }) } @@ -214,11 +217,12 @@ func oauthCallback(ctx echo.Context) error { code = http.StatusBadRequest } return ctx.Render(code, "oauth_callback.html", map[string]interface{}{ - "Success": response.Success, - "ErrorMessage": response.ErrorMessage, - "AccessToken": response.AccessToken, - "ExpiresIn": response.ExpiresIn, - "IdToken": response.IdToken, + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + "Success": response.Success, + "ErrorMessage": response.ErrorMessage, + "AccessToken": response.AccessToken, + "ExpiresIn": response.ExpiresIn, + "IdToken": response.IdToken, }) } @@ -241,5 +245,7 @@ func oauthLogout(ctx echo.Context) error { return ctx.Redirect(http.StatusFound, url) } - return ctx.Render(http.StatusOK, "oauth_logout.html", map[string]interface{}{}) + return ctx.Render(http.StatusOK, "oauth_logout.html", map[string]interface{}{ + "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, + }) } diff --git a/pkg/config/config.go b/pkg/config/config.go index 2c69556..45a71fa 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -30,10 +30,11 @@ type Config struct { // Server contains settings for http application. type Server struct { - Port int `envconfig:"PORT" required:"false" default:"8080"` - Debug bool `envconfig:"DEBUG" required:"false" default:"true"` - AllowOrigins []string `envconfig:"ALLOW_ORIGINS" required:"false" default:"*"` - AllowCredentials bool `envconfig:"ALLOW_CREDENTIALS" required:"false" default:"true"` + Port int `envconfig:"PORT" required:"false" default:"8080"` + Debug bool `envconfig:"DEBUG" required:"false" default:"true"` + AllowOrigins []string `envconfig:"ALLOW_ORIGINS" required:"false" default:"*"` + AllowCredentials bool `envconfig:"ALLOW_CREDENTIALS" required:"false" default:"true"` + AuthWebFormSdkUrl string `envconfig:"AUTH_WEB_FORM_SDK_URL" required:"false" default:"https://static.protocol.one/auth/form/dev/auth-web-form.js"` } // Database contains settings for connection to the database. diff --git a/pkg/manager/change_password.go b/pkg/manager/change_password.go index 9e244b3..220d353 100644 --- a/pkg/manager/change_password.go +++ b/pkg/manager/change_password.go @@ -2,6 +2,7 @@ package manager import ( "fmt" + "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" @@ -25,11 +26,13 @@ type ChangePasswordManager struct { r service.InternalRegistry userIdentityService service.UserIdentityServiceInterface identityProviderService service.AppIdentityProviderServiceInterface + ApiCfg *config.Server } // NewChangePasswordManager return new change password manager. -func NewChangePasswordManager(db database.MgoSession, ir service.InternalRegistry) ChangePasswordManagerInterface { +func NewChangePasswordManager(db database.MgoSession, ir service.InternalRegistry, apiCfg *config.Server) ChangePasswordManagerInterface { m := &ChangePasswordManager{ + ApiCfg: apiCfg, r: ir, userIdentityService: service.NewUserIdentityService(db), identityProviderService: service.NewAppIdentityProviderService(), diff --git a/pkg/manager/change_password_test.go b/pkg/manager/change_password_test.go index e2cf0d7..f2f7b5b 100644 --- a/pkg/manager/change_password_test.go +++ b/pkg/manager/change_password_test.go @@ -14,7 +14,7 @@ import ( func TestChangePasswordManager(t *testing.T) { s := &mocks.MgoSession{} s.On("DB", mock.Anything).Return(&mgo.Database{}) - m := NewChangePasswordManager(s, &mocks.InternalRegistry{}) + m := NewChangePasswordManager(s, &mocks.InternalRegistry{}, nil) assert.Implements(t, (*ChangePasswordManagerInterface)(nil), m) } diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index daea9f6..8611b4c 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -89,11 +89,13 @@ type OauthManager struct { identityProviderService service.AppIdentityProviderServiceInterface r service.InternalRegistry session service.SessionService + ApiCfg *config.Server } // NewOauthManager return new oauth manager. -func NewOauthManager(db database.MgoSession, r service.InternalRegistry, s *config.Session, h *config.Hydra) OauthManagerInterface { +func NewOauthManager(db database.MgoSession, r service.InternalRegistry, s *config.Session, h *config.Hydra, apiCfg *config.Server) OauthManagerInterface { m := &OauthManager{ + ApiCfg: apiCfg, hydraConfig: h, r: r, userService: service.NewUserService(db), diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 19ab2bb..d400a25 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -17,7 +17,7 @@ import ( func TestOauthManager(t *testing.T) { s := &mocks.MgoSession{} s.On("DB", mock.Anything).Return(&mgo.Database{}) - m := NewOauthManager(s, &mocks.InternalRegistry{}, &config.Session{Name: ""}, &config.Hydra{}) + m := NewOauthManager(s, &mocks.InternalRegistry{}, &config.Session{Name: ""}, &config.Hydra{}, nil) assert.Implements(t, (*OauthManagerInterface)(nil), m) } diff --git a/public/templates/change_password.html b/public/templates/change_password.html index 44531b8..be07142 100644 --- a/public/templates/change_password.html +++ b/public/templates/change_password.html @@ -19,6 +19,6 @@ clientId: {{index . "ClientID"}} }; - + diff --git a/public/templates/login_form.html b/public/templates/login_form.html deleted file mode 100644 index e32fb85..0000000 --- a/public/templates/login_form.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - ProtocolONE Auth - - - - -
- - - - diff --git a/public/templates/oauth_callback.html b/public/templates/oauth_callback.html index ff07976..81f4a7b 100644 --- a/public/templates/oauth_callback.html +++ b/public/templates/oauth_callback.html @@ -17,6 +17,6 @@

{{index . "Success"}}

id_token: "{{index . "IdToken"}}", }; - + \ No newline at end of file diff --git a/public/templates/oauth_login.html b/public/templates/oauth_login.html index bedafd5..ad98172 100644 --- a/public/templates/oauth_login.html +++ b/public/templates/oauth_login.html @@ -24,7 +24,7 @@ {{ end }}] }; - + diff --git a/public/templates/oauth_logout.html b/public/templates/oauth_logout.html index 4b7a021..2db68c2 100644 --- a/public/templates/oauth_logout.html +++ b/public/templates/oauth_logout.html @@ -10,6 +10,6 @@ - + \ No newline at end of file From 5246dbc875ffdf994854f5011764a3b51ad2898e Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Thu, 24 Oct 2019 16:44:44 +0300 Subject: [PATCH 002/251] Update deps --- go.sum | 85 ---------------------------------------------------------- 1 file changed, 85 deletions(-) diff --git a/go.sum b/go.sum index 22654f5..bb0b028 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.31.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.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= -cloud.google.com/go v0.37.2 h1:4y4L7BdHenTfZL0HervofNTHh9Ad6mNX72cQvl+5eH0= cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= contrib.go.opencensus.io/exporter/stackdriver v0.7.0/go.mod h1:hNe5qQofPbg6bLQY5wHCvQ7o+2E5P8PkegEuQ+MyRw0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= @@ -22,15 +21,11 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb h1:xexVnYD1Eo/1+d2Mxnl/z82wkIYDEzcK8CZLNwDQyyk= github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb/go.mod h1:cAqWSwjCImM8kWcq/DjvE/ccyQdVpz3GafmV7pl0Ncc= github.com/ProtocolONE/go-micro-plugins v0.2.0/go.mod h1:/gvuHZoDRGfxS+ox0fHXuwwsTEVEHWRWKOhzbnozrZ8= -github.com/ProtocolONE/mfa-service v0.1.0 h1:wWqwaDkiWBdPG88M96zk1Xw8qsyNzTpCTCjAgtLCFC8= github.com/ProtocolONE/mfa-service v0.1.0/go.mod h1:hDh/QJGVolwXb/I20w7p5LHaRQPe44t/7TbPnLVtr3M= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -42,16 +37,12 @@ github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+Dx github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.31/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= -github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/casbin/casbin v1.4.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= @@ -71,7 +62,6 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 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/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/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -91,58 +81,43 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU= github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.0 h1:guf3T2lnCBKlODmERt4T9GtMWRpJOikgKGyIvi0xcb8= github.com/go-openapi/errors v0.19.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0 h1:KVRzjXpMzgdM4GEMDmDTnGcY5yBwGWreJwmmk4k35yU= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0 h1:oP2OUNdG1l2r5kYhrfVMXO54gWmzcfAwP/GFuHpNTkE= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8= github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.0 h1:SF5vyj6PBFM6D1cw2NJIFrlS8Su2YKk6ADPPjAH70Bw= github.com/go-openapi/validate v0.19.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -339,12 +314,9 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:ovBFgdmJqyggKzXS0i5+osE+RsPEbEsUfp2sVCgys1Q= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= @@ -354,24 +326,20 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190309163659-77426154d546/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= -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.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -379,41 +347,28 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= -github.com/hashicorp/consul v1.4.0 h1:PQTW4xCuAExEiSbhrsFsikzbW5gVBoi74BjUvYFyKHw= github.com/hashicorp/consul v1.4.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.1 h1:mYs6SMzu72+90OcPa5wr3nfznA4Dw9UyR791ZFNOIf4= github.com/hashicorp/serf v0.8.1/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs= github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= @@ -439,7 +394,6 @@ github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -451,17 +405,11 @@ 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/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06NeXJqxT468ZqJhy0xPhV1969gVmN+OBL8W8= github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= -github.com/labstack/echo/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= -github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= -github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e h1:BsBWIgqA7BFb5sdQeFVQqXYL0P9ZwiNYvL3nywtEmnY= github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= -github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe h1:S7XSBlgc/eI2v47LkPPVa+infH3FuTS4tPJbqCtJovo= github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe/go.mod h1:zvUY6gZZVL2nu7NM+/3b51Z/hxyFZCZxV0hvfZ3NJlg= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= @@ -469,7 +417,6 @@ github.com/luna-duclos/instrumentedsql v0.0.0-20190316074304-ecad98b20aec/go.mod github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= @@ -492,12 +439,10 @@ github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGf github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA= github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -505,39 +450,29 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod h1:Ylx55XGW4gjY7McWT0pgqU0aQquIOChDnYkOVbSuF/c= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= -github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300 h1:MmeZIBmcbV9QSh0NQOC3vTgL/KoJvnrGugr+FBI3POM= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= github.com/micro/go-api v0.5.0/go.mod h1:itWuEfGqJNM5q5hct5LWYFSxwPZWyngnrRpgMQJxlA0= github.com/micro/go-bot v0.0.0-20190110110712-d02abe15d72c/go.mod h1:LJbtcpqRNyOrHrNnhLPiexIUb9ErxDSeWIJbj1UB9hQ= github.com/micro/go-grpc v0.7.0/go.mod h1:m8NMevmhL63muB3I1AnI8uf7YaW4YVjNIDW8PpQPRg8= -github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6 h1:Nz+rX1q6rJLAQcLBB6maXYUmSvcdzJR2OArDKCDkco4= github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6/go.mod h1:QikSuviYcIE8V0CY4e0RRqVs3Oh8EuzX+qCEOnh9Qh8= -github.com/micro/go-micro v0.22.1 h1:U4gZPakGOhG1ypJw+kgQ1+O0JkDePntGjcdc7WSoR0E= github.com/micro/go-micro v0.22.1/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= github.com/micro/go-plugins v0.21.0/go.mod h1:dNzFjp55RfRhGm7zC6tPPzbdnAPo8+Yq4DbgEWdx6gc= -github.com/micro/go-rcache v0.0.0-20180418165751-a581a57b5133 h1:hA0jzfRMat31ugTTK3BQfxGSuh7zD4Or/lEo/4edJiE= github.com/micro/go-rcache v0.0.0-20180418165751-a581a57b5133/go.mod h1:CBzgfnsCYHcyLg1qeTShF0iDErQmcLmSt+SdwjLkckI= github.com/micro/grpc-go v0.0.0-20180913204047-2c703400301b/go.mod h1://clyXyptX/KfdauimE3DJIvC/TKOioMd9rb5blDZmI= -github.com/micro/h2c v1.0.0 h1:ejw6MS5+WaUoMHRtqkVCCrrVzLMzOFEH52rEyd8Fl2I= github.com/micro/h2c v1.0.0/go.mod h1:54sOOQW/GRlHhH43vKwOhUb+kHaXhVxR0d3CJhn9alE= github.com/micro/hipchat v0.0.0-20160328000638-4c67119ac956/go.mod h1:9LPnmAqs2JarMBCqn4eUNkATVCsGQFphxNoQEi28uLU= github.com/micro/kubernetes v0.2.0/go.mod h1:YMCRhiXTTNCND35/YcgACDFd1tOTmrDFAEqsvkID6pw= -github.com/micro/mdns v0.0.0-20181201230301-9c3770d4057a h1:QD0DngoQMpPt8pvimhNtIJiocn4C+IyqpazrEYX1lHo= github.com/micro/mdns v0.0.0-20181201230301-9c3770d4057a/go.mod h1:SQG6o/94RinohLuB5noHSevg2Iqg2wXLDUn4lj2LWWo= github.com/micro/micro v0.20.0/go.mod h1:fkfl/b2vWYkKiUgYW/3uw8OVZTxE/ARw761basyjcBY= github.com/micro/protoc-gen-micro v0.5.0/go.mod h1:QgEs4oW0uXue7N3WxGFDbOKXaMLyt0mEjOZghByrgpc= -github.com/micro/util v0.0.0-20181115195001-2d4f591dc538 h1:8kG8BwYfwa3XApLhHmPkoPq4qiQjKQZR8XA024LPrq4= github.com/micro/util v0.0.0-20181115195001-2d4f591dc538/go.mod h1:vxd7TGn28ynEMF4szG3PHTzgo3bx3FpfON9xpFsGc+g= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.2 h1:Y/HbdlkFiiRU3Njr3hRk0KFKinYX90x7wtQMZvxShJo= github.com/miekg/dns v1.1.2/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 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= @@ -572,7 +507,6 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8 github.com/ory/graceful v0.1.1/go.mod h1:zqu70l95WrKHF4AZ6tXHvAqAvpY6M7g6ttaAVcMm7KU= github.com/ory/herodot v0.5.1/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= github.com/ory/herodot v0.6.0/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= -github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 h1:B95NIi2iuJ/zSuHByMvUQKa9lJH+6F3kxc+0BIjzzrU= github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12/go.mod h1:a0vgfecHsymehd3DuihIJxv5KMGJXpXVzD9IuKS7Vas= github.com/ory/x v0.0.49/go.mod h1:LVQf17Z8SK/y0H0ewDuIqJLDCjQ2eOIfQT5l0LH53ls= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= @@ -582,12 +516,10 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0= github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -614,7 +546,6 @@ github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= @@ -660,12 +591,10 @@ github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -686,11 +615,8 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= -github.com/xakep666/mongo-migrate v0.1.0 h1:S8pnQJgcmnGI7LWUH7XJP4gOU9FO1MIB00Q3lGIDC64= github.com/xakep666/mongo-migrate v0.1.0/go.mod h1:8Nv3hSnx/kf3VG4njmsUoMzeNoftRT/zmypXlKD9ojY= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -703,11 +629,8 @@ go.opencensus.io v0.19.0/go.mod h1:AYeH0+ZxYyghG8diqaaIq/9P3VgCCt5GF2ldCY4dkFg= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= go.opencensus.io v0.20.0/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= @@ -736,7 +659,6 @@ golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -770,7 +692,6 @@ golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73r 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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190326090315-15845e8f865b h1:LlDMQZ0I/u8J45sbt31TecpsFNErRGwDgS4WvT9hKzE= golang.org/x/net v0.0.0-20190326090315-15845e8f865b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180603041954-1e0a3fa8ba9a/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -780,7 +701,6 @@ golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -821,7 +741,6 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -896,9 +815,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.26.0 h1:2NPPsBpD0ZoxshmLWewQru8rWmbT5JqSzz9D1ZrAjYQ= gopkg.in/go-playground/validator.v9 v9.26.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -911,12 +828,10 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20140626144623-14b3d72120e8/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= -gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= From cccff09cfb07af26be6d190ae9f3283d55a3a343 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Thu, 24 Oct 2019 17:00:57 +0300 Subject: [PATCH 003/251] Update deps --- go.mod | 1 - go.sum | 1 - 2 files changed, 2 deletions(-) diff --git a/go.mod b/go.mod index 5ee536e..e2b840b 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-isatty v0.0.6 // indirect github.com/micro/go-api v0.5.0 // indirect - github.com/micro/go-bot v0.0.0-20190110110712-d02abe15d72c // indirect github.com/micro/go-micro v0.22.1 github.com/micro/grpc-go v0.0.0-20180913204047-2c703400301b // indirect github.com/micro/hipchat v0.0.0-20160328000638-4c67119ac956 // indirect diff --git a/go.sum b/go.sum index bb0b028..2344864 100644 --- a/go.sum +++ b/go.sum @@ -452,7 +452,6 @@ github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= github.com/micro/go-api v0.5.0/go.mod h1:itWuEfGqJNM5q5hct5LWYFSxwPZWyngnrRpgMQJxlA0= -github.com/micro/go-bot v0.0.0-20190110110712-d02abe15d72c/go.mod h1:LJbtcpqRNyOrHrNnhLPiexIUb9ErxDSeWIJbj1UB9hQ= github.com/micro/go-grpc v0.7.0/go.mod h1:m8NMevmhL63muB3I1AnI8uf7YaW4YVjNIDW8PpQPRg8= github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6/go.mod h1:QikSuviYcIE8V0CY4e0RRqVs3Oh8EuzX+qCEOnh9Qh8= github.com/micro/go-micro v0.22.1/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= From 80f3813785a740f67075f880d3f45be15a82e571 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Thu, 24 Oct 2019 17:29:52 +0300 Subject: [PATCH 004/251] Update deps --- cmd/server.go | 2 +- go.mod | 44 ++-- go.sum | 708 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 703 insertions(+), 51 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index c701ae5..c8cc249 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -9,7 +9,7 @@ import ( "github.com/boj/redistore" "github.com/go-redis/redis" "github.com/micro/go-micro" - "github.com/micro/go-plugins/selector/static" + "github.com/micro/go-plugins/client/selector/static" "github.com/ory/hydra/sdk/go/hydra/client" "github.com/spf13/cobra" "go.uber.org/zap" diff --git a/go.mod b/go.mod index e2b840b..22fb6f1 100644 --- a/go.mod +++ b/go.mod @@ -1,70 +1,58 @@ module github.com/ProtocolONE/auth1.protocol.one require ( - contrib.go.opencensus.io/exporter/stackdriver v0.7.0 // indirect git.apache.org/thrift.git v0.12.0 // indirect github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb github.com/ProtocolONE/mfa-service v0.1.0 + github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect github.com/alicebob/miniredis v2.5.0+incompatible + github.com/apache/thrift v0.12.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/elliotchance/redismock v1.5.1 - github.com/ghodss/yaml v1.0.0 // indirect + github.com/fatih/structs v1.1.0 // indirect github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/go-openapi/runtime v0.19.0 github.com/go-openapi/strfmt v0.19.0 github.com/go-openapi/swag v0.19.0 - github.com/go-playground/locales v0.12.1 // indirect - github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-redis/redis v6.15.2+incompatible github.com/golang/oauth2 v0.0.0-20181203162652-d668ce993890 - github.com/golang/protobuf v1.3.1 - github.com/google/pprof v0.0.0-20190309163659-77426154d546 // indirect + github.com/golang/protobuf v1.3.2 github.com/google/uuid v1.1.1 - github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.1.3 - github.com/gorilla/websocket v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.6.2 // indirect github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 - github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 // indirect github.com/juju/mgosession v1.0.0 // indirect github.com/kelseyhightower/envconfig v1.3.0 github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 github.com/labstack/echo/v4 v4.0.0 github.com/labstack/gommon v0.2.8 - github.com/leodido/go-urn v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.1 // indirect - github.com/mattn/go-isatty v0.0.6 // indirect - github.com/micro/go-api v0.5.0 // indirect - github.com/micro/go-micro v0.22.1 - github.com/micro/grpc-go v0.0.0-20180913204047-2c703400301b // indirect - github.com/micro/hipchat v0.0.0-20160328000638-4c67119ac956 // indirect - github.com/micro/micro v0.20.0 // indirect - github.com/micro/protoc-gen-micro v0.5.0 // indirect - github.com/miekg/dns v1.1.2 // indirect - github.com/nlopes/slack v0.4.0 // indirect + github.com/micro/go-micro v1.8.0 + github.com/micro/go-plugins v1.2.0 + github.com/openzipkin/zipkin-go v0.1.6 // indirect github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 github.com/pkg/errors v0.8.1 - github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 // indirect - github.com/sirupsen/logrus v1.4.0 + github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.3 github.com/spf13/viper v1.3.2 github.com/stretchr/testify v1.3.0 github.com/xakep666/mongo-migrate v0.1.0 - github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect - go.uber.org/zap v1.9.1 - golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c - golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a - gopkg.in/go-playground/validator.v9 v9.26.0 + go.uber.org/zap v1.10.0 + golang.org/x/build v0.0.0-20190314133821-5284462c4bec // indirect + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + gopkg.in/go-playground/validator.v9 v9.29.1 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect gopkg.in/yaml.v2 v2.2.2 ) + +replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.1 diff --git a/go.sum b/go.sum index 2344864..c6d9d48 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,23 @@ -cloud.google.com/go v0.23.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.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.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= -contrib.go.opencensus.io/exporter/stackdriver v0.7.0/go.mod h1:hNe5qQofPbg6bLQY5wHCvQ7o+2E5P8PkegEuQ+MyRw0= +cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= +cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= +contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= +contrib.go.opencensus.io/exporter/ocagent v0.5.1/go.mod h1:oGSyf701BHqn69lMacwJJuyGzrk5eiCj86DxXhG2gfk= +contrib.go.opencensus.io/exporter/stackdriver v0.11.0/go.mod h1:hA7rlmtavV03FGxzWXAPBUnZeZBhWN/QYQAuMtxc9Bk= +contrib.go.opencensus.io/exporter/stackdriver v0.12.4/go.mod h1:fmn/xkyUfUhd1iD7Ic+HSN8y11KhSK5oe8CWfSjKa7M= +contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +contrib.go.opencensus.io/resource v0.0.0-20190131005048-21591786a5e0/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= +contrib.go.opencensus.io/resource v0.1.2/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= @@ -12,118 +25,295 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20181218151757-9b75e4fe745a/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-amqp-common-go v1.1.3/go.mod h1:FhZtXirFANw40UXI2ntweO+VOkfaw8s6vZxUiRhLYW8= +github.com/Azure/azure-amqp-common-go v1.1.4/go.mod h1:FhZtXirFANw40UXI2ntweO+VOkfaw8s6vZxUiRhLYW8= +github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go v16.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v27.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v32.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-service-bus-go v0.4.1/go.mod h1:d9ho9e/06euiTwGpKxmlbpPhFUsfCsq6a4tZ68r51qI= +github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= +github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.7.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v10.15.3+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v11.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v11.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v12.3.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= 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 v0.0.0-20160329135253-cc2f4770f4d6/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190418212003-6ac0b49e7197/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190725230627-253d1edd4416/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= github.com/InVisionApp/go-health v2.1.0+incompatible/go.mod h1:/+Gv1o8JUsrjC6pi6MN6/CgKJo4OqZ6x77XAnImrzhg= github.com/InVisionApp/go-logger v1.0.1/go.mod h1:+cGTDSn+P8105aZkeOfIhdd7vFO5X1afUHcjvanY0L8= +github.com/Jeffail/gabs v1.1.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Microsoft/go-winio v0.4.3/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb h1:xexVnYD1Eo/1+d2Mxnl/z82wkIYDEzcK8CZLNwDQyyk= github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb/go.mod h1:cAqWSwjCImM8kWcq/DjvE/ccyQdVpz3GafmV7pl0Ncc= github.com/ProtocolONE/go-micro-plugins v0.2.0/go.mod h1:/gvuHZoDRGfxS+ox0fHXuwwsTEVEHWRWKOhzbnozrZ8= +github.com/ProtocolONE/mfa-service v0.1.0 h1:wWqwaDkiWBdPG88M96zk1Xw8qsyNzTpCTCjAgtLCFC8= github.com/ProtocolONE/mfa-service v0.1.0/go.mod h1:hDh/QJGVolwXb/I20w7p5LHaRQPe44t/7TbPnLVtr3M= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= +github.com/RoaringBitmap/roaring v0.4.18/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= +github.com/SAP/go-hdb v0.12.0/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0= +github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/abbot/go-http-auth v0.4.1-0.20181019201920-860ed7f246ff/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= +github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 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/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= +github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= +github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= +github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= +github.com/anacrolix/missinggo v1.1.1/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= +github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk= +github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= +github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= +github.com/anacrolix/utp v0.0.0-20180219060659-9e0e1d1d0572/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= +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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.15.31/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/asim/go-awsxray v0.0.0-20161209120537-0d8a60b6e205/go.mod h1:frVmN4PtXUuL1EbZn0uL4PHSTKNKFnbMpBIhngqMuNQ= +github.com/asim/go-bson v0.0.0-20160318195205-84522947cabd/go.mod h1:L59ZX7HuzTbNzFBt8g3SJkRraj+GBOgvLAfJYJUcQ5w= +github.com/aws/aws-sdk-go v1.15.24/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.18.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.16/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.21.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.21.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= 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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= +github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= +github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/casbin/casbin v1.4.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= 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 v0.0.0-20161109192337-d17a8420c36e/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.0.0-20161110002650-365d370cc145/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20180326210544-5e605d46809c/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/denisenkom/go-mssqldb v0.0.0-20180620032804-94c9c97e8c9f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +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/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= +github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= +github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elliotchance/redismock v1.5.1/go.mod h1:8FFsGWghPUyP7nqj/UYXr2xqd6U2iNMxS4S5+Xadl5A= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.0.0-20180919002855-2137d9196328/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v0.0.0-20180123065059-ebf56d35bba7/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY= +github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20181003173013-ead4ad1d2727/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= +github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/go-unsnap-stream v0.0.0-20190730064659-98d31706395a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= 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-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU= github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.0 h1:guf3T2lnCBKlODmERt4T9GtMWRpJOikgKGyIvi0xcb8= github.com/go-openapi/errors v0.19.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0 h1:KVRzjXpMzgdM4GEMDmDTnGcY5yBwGWreJwmmk4k35yU= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0 h1:oP2OUNdG1l2r5kYhrfVMXO54gWmzcfAwP/GFuHpNTkE= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8= github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.0 h1:SF5vyj6PBFM6D1cw2NJIFrlS8Su2YKk6ADPPjAH70Bw= github.com/go-openapi/validate v0.19.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redsync/redsync v1.3.0/go.mod h1:QClK/s99KRhfKdpxLTMsI5mSu43iLp0NfOneLPie+78= +github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stomp/stomp v2.0.3+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= github.com/go-swagger/go-swagger v0.19.0/go.mod h1:fOcXeMI1KPNv3uk4u7cR4VSyq0NyrYx4SS1/ajuTWDg= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= +github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4= github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs= @@ -300,90 +490,222 @@ github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUCh github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v0.0.0-20190410021324-65acae22fc9/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20181116215533-9bd4a3295021/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20190312205958-5a2505f3dbf0/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:ovBFgdmJqyggKzXS0i5+osE+RsPEbEsUfp2sVCgys1Q= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +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-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +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 v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190309163659-77426154d546/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-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.2.2/go.mod h1:7FHVg6mFpFQrjeUZrm+BaD50N5jnDKm50uVPTpyYOmU= +github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 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/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= +github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +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.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/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.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= -github.com/hashicorp/consul v1.4.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4c= +github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= +github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= +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 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-bexpr v0.1.0/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU= +github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-discover v0.0.0-20190403160810-22221edb15cd/go.mod h1:ueUgD9BeIocT7QNuvxSyJyPAM9dfifBcaWmeybb67OY= +github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= +github.com/hashicorp/go-retryablehttp v0.0.0-20180531211321-3b087ef2d313/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= +github.com/hashicorp/go-rootcerts v1.0.1/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 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +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-version v0.0.0-20170202080759-03c5bf6be031/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +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.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v0.0.0-20180906183839-65a6292f0157/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hil v0.0.0-20160711231837-1e86c6b523c5/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts= +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/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= +github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= +github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= +github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= +github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= +github.com/hashicorp/raft-boltdb v0.0.0-20150201200839-d1e82c1ec3f1/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/hashicorp/raft-boltdb v0.0.0-20190605210249-ef2e128ed477/go.mod h1:aUF6HQr8+t3FC/ZHAC+pZreUBhTaxumuu3L+d37uRxk= github.com/hashicorp/serf v0.8.1/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= +github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= +github.com/hashicorp/vault v0.10.3/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= +github.com/hashicorp/vault v1.1.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= +github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190318174639-195e0e9d07f1/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0= +github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/hudl/fargo v1.2.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs= github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA= +github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20160818025724-3b7ece48644d/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/mgosession v1.0.0/go.mod h1:4zVjdmPhtQ+tFwByzM8UcGYKEqqiG9TvPArt210VNw4= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= @@ -394,8 +716,15 @@ github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -404,19 +733,35 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB 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/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06NeXJqxT468ZqJhy0xPhV1969gVmN+OBL8W8= github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= +github.com/labstack/echo/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= +github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e h1:BsBWIgqA7BFb5sdQeFVQqXYL0P9ZwiNYvL3nywtEmnY= github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= +github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe h1:S7XSBlgc/eI2v47LkPPVa+infH3FuTS4tPJbqCtJovo= github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe/go.mod h1:zvUY6gZZVL2nu7NM+/3b51Z/hxyFZCZxV0hvfZ3NJlg= +github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA= +github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= github.com/luna-duclos/instrumentedsql v0.0.0-20190316074304-ecad98b20aec/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.0-20180911180927-64fcb82c878e/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= @@ -436,14 +781,22 @@ github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -451,45 +804,98 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod h1:Ylx55XGW4gjY7McWT0pgqU0aQquIOChDnYkOVbSuF/c= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= -github.com/micro/go-api v0.5.0/go.mod h1:itWuEfGqJNM5q5hct5LWYFSxwPZWyngnrRpgMQJxlA0= +github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= +github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/go-grpc v0.7.0/go.mod h1:m8NMevmhL63muB3I1AnI8uf7YaW4YVjNIDW8PpQPRg8= github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6/go.mod h1:QikSuviYcIE8V0CY4e0RRqVs3Oh8EuzX+qCEOnh9Qh8= github.com/micro/go-micro v0.22.1/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= +github.com/micro/go-micro v1.8.0 h1:4etDwf3DqP61cM0xrI+3OP+FlAsRUnM2rwBXFRTrl+Y= +github.com/micro/go-micro v1.8.0/go.mod h1:RUJTXVb+qUnGx6jBK2yMCOzuB/xEKh/vdZc3uagM5TI= github.com/micro/go-plugins v0.21.0/go.mod h1:dNzFjp55RfRhGm7zC6tPPzbdnAPo8+Yq4DbgEWdx6gc= +github.com/micro/go-plugins v1.2.0 h1:/p9EzqJUiKkldzhANbu4hgKOaQufSBBwusQyhhvfjv8= +github.com/micro/go-plugins v1.2.0/go.mod h1:N2UCiG7ExrTZ1N1dq1PF9bOgtuBOlUVEc86rfNGqxFQ= +github.com/micro/go-plugins v1.3.0 h1:zRXJ3zNfjVU5HSA1TC6spPpd7f5bJRtNylxWS1ONbR0= github.com/micro/go-rcache v0.0.0-20180418165751-a581a57b5133/go.mod h1:CBzgfnsCYHcyLg1qeTShF0iDErQmcLmSt+SdwjLkckI= -github.com/micro/grpc-go v0.0.0-20180913204047-2c703400301b/go.mod h1://clyXyptX/KfdauimE3DJIvC/TKOioMd9rb5blDZmI= github.com/micro/h2c v1.0.0/go.mod h1:54sOOQW/GRlHhH43vKwOhUb+kHaXhVxR0d3CJhn9alE= -github.com/micro/hipchat v0.0.0-20160328000638-4c67119ac956/go.mod h1:9LPnmAqs2JarMBCqn4eUNkATVCsGQFphxNoQEi28uLU= github.com/micro/kubernetes v0.2.0/go.mod h1:YMCRhiXTTNCND35/YcgACDFd1tOTmrDFAEqsvkID6pw= github.com/micro/mdns v0.0.0-20181201230301-9c3770d4057a/go.mod h1:SQG6o/94RinohLuB5noHSevg2Iqg2wXLDUn4lj2LWWo= -github.com/micro/micro v0.20.0/go.mod h1:fkfl/b2vWYkKiUgYW/3uw8OVZTxE/ARw761basyjcBY= -github.com/micro/protoc-gen-micro v0.5.0/go.mod h1:QgEs4oW0uXue7N3WxGFDbOKXaMLyt0mEjOZghByrgpc= +github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= +github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= +github.com/micro/micro v1.8.0/go.mod h1:dF7nfyek86puqmlN1cEeyCos98rGzprwehRKJ4HMudE= github.com/micro/util v0.0.0-20181115195001-2d4f591dc538/go.mod h1:vxd7TGn28ynEMF4szG3PHTzgo3bx3FpfON9xpFsGc+g= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.2/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v0.0.0-20160804032330-cdac8253d00f/go.mod h1:eOsF2yLPlBBJPvD+nhl5QMTBSOBbOph6N7j/IDUw7PY= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= +github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +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.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.2.6/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= +github.com/nats-io/jwt v0.2.8/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= +github.com/nats-io/jwt v0.2.12/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= +github.com/nats-io/nats-server/v2 v2.0.0/go.mod h1:RyVdsHHvY4B6c9pWG+uRLpZ0h0XsqiuKp2XCTurP5LI= +github.com/nats-io/nats-server/v2 v2.0.2/go.mod h1:sk9mvTwGZiqHrkA12dw2r6LKmPYPkw15tB8haEsvxo8= +github.com/nats-io/nats-streaming-server v0.15.1/go.mod h1:bJ1+2CS8MqvkGfr/NwnCF+Lw6aLnL3F5kenM8bZmdCw= +github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nats-io/stan.go v0.4.5/go.mod h1:Ji7mK6gRZJSH1nc3ZJH6vi7zn/QnZhpR9Arm4iuzsUQ= +github.com/nats-io/stan.go v0.5.0/go.mod h1:dYqB+vMN3C2F9pT1FRQpg9eHbjPj6mP0yYuyBNuXHZE= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= -github.com/nlopes/slack v0.4.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= +github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= +github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= +github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito= +github.com/oklog/run v0.0.0-20180308005104-6934b124db28/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -506,50 +912,86 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8 github.com/ory/graceful v0.1.1/go.mod h1:zqu70l95WrKHF4AZ6tXHvAqAvpY6M7g6ttaAVcMm7KU= github.com/ory/herodot v0.5.1/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= github.com/ory/herodot v0.6.0/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= +github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 h1:B95NIi2iuJ/zSuHByMvUQKa9lJH+6F3kxc+0BIjzzrU= github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12/go.mod h1:a0vgfecHsymehd3DuihIJxv5KMGJXpXVzD9IuKS7Vas= github.com/ory/x v0.0.49/go.mod h1:LVQf17Z8SK/y0H0ewDuIqJLDCjQ2eOIfQT5l0LH53ls= +github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= 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 v0.0.0-20180527043350-9f6ff22cfff8/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= +github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0= github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= +github.com/prometheus/client_golang v0.0.0-20180328130430-f504d69affe1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180326160409-38c53a9f4bfc/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181218105931-67670fe90761/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190328153300-af7bedc223fb/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= +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.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +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/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= +github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -581,31 +1023,60 @@ github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= +github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/webbrowser v0.0.0-20150720201625-21fc9f95c834/go.mod h1:Hqqqmzj8AHn+VlZyVjaRWY20i25hoOZGAABCcg2el4A= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= @@ -614,24 +1085,51 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= +github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xakep666/mongo-migrate v0.1.0 h1:S8pnQJgcmnGI7LWUH7XJP4gOU9FO1MIB00Q3lGIDC64= github.com/xakep666/mongo-migrate v0.1.0/go.mod h1:8Nv3hSnx/kf3VG4njmsUoMzeNoftRT/zmypXlKD9ojY= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.mongodb.org/mongo-driver v1.0.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.0.4/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.19.0/go.mod h1:AYeH0+ZxYyghG8diqaaIq/9P3VgCCt5GF2ldCY4dkFg= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= go.opencensus.io v0.20.0/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +gocloud.dev v0.15.0/go.mod h1:ShXCyJaGrJu9y/7a6+DSCyBb9MFGZ1P5wwPa0Wu6w34= +gocloud.dev/pubsub/rabbitpubsub v0.15.0/go.mod h1:LGg5Acwcpry+GeLNaA01xm0Ij43YUis6kht2qRX2tg0= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4= golang.org/x/crypto v0.0.0-20161221235747-f6b343c37ca8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -655,17 +1153,39 @@ golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190718202018-cfdd5522f6f6/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190729225735-1bd0cf576493/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/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/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +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/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -689,10 +1209,26 @@ golang.org/x/net v0.0.0-20190119204137-ed066c81e75e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/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-20190228165749-92fc7df08ae7/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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190322120337-addf6b3196f6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190326090315-15845e8f865b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180603041954-1e0a3fa8ba9a/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/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-20190619014844-b5b0513f8c1b/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 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -701,15 +1237,21 @@ golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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/sys v0.0.0-20161012001920-9bb9f0998d48/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20180831094639-fa5fdf94c789/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/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-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -733,27 +1275,54 @@ golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3/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-20190221075227-b4e8571b14e0/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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/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-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -772,23 +1341,45 @@ golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190118193359-16909d206f00/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-20190315044204-8b67d361bba2/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190402200628-202502a5a924/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/api v0.0.0-20180603000442-8e296ef26005/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/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-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +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-20190624190245-7f2218787638/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-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= -google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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/genproto v0.0.0-20180601223552-81158efcc9f2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -797,40 +1388,86 @@ google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190321212433-e79c0c59cdb5/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/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-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 h1:Ygq9/SRJX9+dU0WCIICM8RkWvDw03lvB77hrhJnpxfU= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/DataDog/dd-trace-go.v1 v1.16.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.26.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= +gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/juju/names.v2 v2.0.0-20180621093930-fd59336b4621/go.mod h1:XXa/v5qG1IsStRg5KTE8JkDMndoDMOKH1YYw0jSUWaM= +gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= +gopkg.in/redis.v3 v3.6.4/go.mod h1:6XeGv/CrsUFDU9aVbUdNykN7k1zVmoeg83KC9RbQfiU= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= +gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20140626144623-14b3d72120e8/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= +gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= @@ -838,5 +1475,32 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= +honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.0.0-20180806132203-61b11ee65332/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20190325185214-7544f9db76f6/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20190726022912-69e1bce1dad5/go.mod h1:V6cpJ9D7WqSy0wqcE096gcbj+W//rshgQgmj1Shdwi8= +k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190726022757-641a75999153/go.mod h1:eXR4ljjmbwK6Ng0PKsXRySPXnTUy/qBUa6kPDeckhQ0= +k8s.io/apimachinery v0.0.0-20190727130956-f97a4e5b4abc/go.mod h1:eXR4ljjmbwK6Ng0PKsXRySPXnTUy/qBUa6kPDeckhQ0= +k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= +k8s.io/utils v0.0.0-20190712204705-3dccf664f023/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +pack.ag/amqp v0.8.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +pack.ag/amqp v0.11.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +pack.ag/amqp v0.12.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= From f919f4e88ee88dd4f746a44f3a1b22d1ae8f0259 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Thu, 24 Oct 2019 23:15:24 +0300 Subject: [PATCH 005/251] Update deps --- go.mod | 4 +-- go.sum | 105 ++++----------------------------------------------------- 2 files changed, 8 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index 22fb6f1..3890aef 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ProtocolONE/auth1.protocol.one require ( git.apache.org/thrift.git v0.12.0 // indirect github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb - github.com/ProtocolONE/mfa-service v0.1.0 + github.com/ProtocolONE/mfa-service v0.1.1 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect @@ -40,7 +40,7 @@ require ( github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.3 github.com/spf13/viper v1.3.2 - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/xakep666/mongo-migrate v0.1.0 github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect go.uber.org/zap v1.10.0 diff --git a/go.sum b/go.sum index c6d9d48..130f908 100644 --- a/go.sum +++ b/go.sum @@ -7,7 +7,6 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= -cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w= cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= @@ -72,17 +71,13 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb h1:xexVnYD1Eo/1+d2Mxnl/z82wkIYDEzcK8CZLNwDQyyk= github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb/go.mod h1:cAqWSwjCImM8kWcq/DjvE/ccyQdVpz3GafmV7pl0Ncc= -github.com/ProtocolONE/go-micro-plugins v0.2.0/go.mod h1:/gvuHZoDRGfxS+ox0fHXuwwsTEVEHWRWKOhzbnozrZ8= -github.com/ProtocolONE/mfa-service v0.1.0 h1:wWqwaDkiWBdPG88M96zk1Xw8qsyNzTpCTCjAgtLCFC8= -github.com/ProtocolONE/mfa-service v0.1.0/go.mod h1:hDh/QJGVolwXb/I20w7p5LHaRQPe44t/7TbPnLVtr3M= +github.com/ProtocolONE/go-micro-plugins v0.3.0/go.mod h1:/gvuHZoDRGfxS+ox0fHXuwwsTEVEHWRWKOhzbnozrZ8= +github.com/ProtocolONE/mfa-service v0.1.1/go.mod h1:8cwQ3Y+ub16gzN13OXVCgIKiN8Rp7czS+KfvJMFs5eU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.18/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= @@ -115,13 +110,11 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= 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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asim/go-awsxray v0.0.0-20161209120537-0d8a60b6e205/go.mod h1:frVmN4PtXUuL1EbZn0uL4PHSTKNKFnbMpBIhngqMuNQ= github.com/asim/go-bson v0.0.0-20160318195205-84522947cabd/go.mod h1:L59ZX7HuzTbNzFBt8g3SJkRraj+GBOgvLAfJYJUcQ5w= @@ -134,14 +127,13 @@ github.com/aws/aws-sdk-go v1.21.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= 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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= @@ -186,7 +178,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.0.0-20180620032804-94c9c97e8c9f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -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/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= @@ -239,7 +230,6 @@ github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -251,7 +241,6 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I 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-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= 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= @@ -259,51 +248,38 @@ github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dT github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU= github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.0 h1:guf3T2lnCBKlODmERt4T9GtMWRpJOikgKGyIvi0xcb8= github.com/go-openapi/errors v0.19.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0 h1:KVRzjXpMzgdM4GEMDmDTnGcY5yBwGWreJwmmk4k35yU= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0 h1:oP2OUNdG1l2r5kYhrfVMXO54gWmzcfAwP/GFuHpNTkE= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8= github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.0 h1:SF5vyj6PBFM6D1cw2NJIFrlS8Su2YKk6ADPPjAH70Bw= github.com/go-openapi/validate v0.19.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redsync/redsync v1.3.0/go.mod h1:QClK/s99KRhfKdpxLTMsI5mSu43iLp0NfOneLPie+78= github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -514,16 +490,13 @@ github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 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= @@ -542,7 +515,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.2.2/go.mod h1:7FHVg6mFpFQrjeUZrm+BaD50N5jnDKm50uVPTpyYOmU= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= @@ -561,7 +533,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -571,11 +542,9 @@ github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= -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.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -589,41 +558,32 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4c= github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= -github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= 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 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.0/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-discover v0.0.0-20190403160810-22221edb15cd/go.mod h1:ueUgD9BeIocT7QNuvxSyJyPAM9dfifBcaWmeybb67OY= github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= github.com/hashicorp/go-retryablehttp v0.0.0-20180531211321-3b087ef2d313/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= github.com/hashicorp/go-rootcerts v1.0.1/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 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= 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= @@ -634,7 +594,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 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.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20180906183839-65a6292f0157/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -643,7 +602,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= @@ -654,7 +612,6 @@ github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pN github.com/hashicorp/raft-boltdb v0.0.0-20190605210249-ef2e128ed477/go.mod h1:aUF6HQr8+t3FC/ZHAC+pZreUBhTaxumuu3L+d37uRxk= github.com/hashicorp/serf v0.8.1/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/vault v0.10.3/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= github.com/hashicorp/vault v1.1.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= @@ -670,7 +627,6 @@ github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwP github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= @@ -681,7 +637,6 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs= github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -695,7 +650,6 @@ github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWx github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -716,7 +670,6 @@ github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -735,17 +688,11 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06NeXJqxT468ZqJhy0xPhV1969gVmN+OBL8W8= github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= -github.com/labstack/echo/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= -github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= -github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e h1:BsBWIgqA7BFb5sdQeFVQqXYL0P9ZwiNYvL3nywtEmnY= github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= -github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe h1:S7XSBlgc/eI2v47LkPPVa+infH3FuTS4tPJbqCtJovo= github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe/go.mod h1:zvUY6gZZVL2nu7NM+/3b51Z/hxyFZCZxV0hvfZ3NJlg= github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -761,7 +708,6 @@ github.com/lyft/protoc-gen-validate v0.0.0-20180911180927-64fcb82c878e/go.mod h1 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= @@ -788,14 +734,12 @@ github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwm github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -804,22 +748,14 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod h1:Ylx55XGW4gjY7McWT0pgqU0aQquIOChDnYkOVbSuF/c= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= -github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= -github.com/micro/go-grpc v0.7.0/go.mod h1:m8NMevmhL63muB3I1AnI8uf7YaW4YVjNIDW8PpQPRg8= github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6/go.mod h1:QikSuviYcIE8V0CY4e0RRqVs3Oh8EuzX+qCEOnh9Qh8= github.com/micro/go-micro v0.22.1/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= -github.com/micro/go-micro v1.8.0 h1:4etDwf3DqP61cM0xrI+3OP+FlAsRUnM2rwBXFRTrl+Y= github.com/micro/go-micro v1.8.0/go.mod h1:RUJTXVb+qUnGx6jBK2yMCOzuB/xEKh/vdZc3uagM5TI= -github.com/micro/go-plugins v0.21.0/go.mod h1:dNzFjp55RfRhGm7zC6tPPzbdnAPo8+Yq4DbgEWdx6gc= -github.com/micro/go-plugins v1.2.0 h1:/p9EzqJUiKkldzhANbu4hgKOaQufSBBwusQyhhvfjv8= github.com/micro/go-plugins v1.2.0/go.mod h1:N2UCiG7ExrTZ1N1dq1PF9bOgtuBOlUVEc86rfNGqxFQ= -github.com/micro/go-plugins v1.3.0 h1:zRXJ3zNfjVU5HSA1TC6spPpd7f5bJRtNylxWS1ONbR0= github.com/micro/go-rcache v0.0.0-20180418165751-a581a57b5133/go.mod h1:CBzgfnsCYHcyLg1qeTShF0iDErQmcLmSt+SdwjLkckI= github.com/micro/h2c v1.0.0/go.mod h1:54sOOQW/GRlHhH43vKwOhUb+kHaXhVxR0d3CJhn9alE= -github.com/micro/kubernetes v0.2.0/go.mod h1:YMCRhiXTTNCND35/YcgACDFd1tOTmrDFAEqsvkID6pw= github.com/micro/mdns v0.0.0-20181201230301-9c3770d4057a/go.mod h1:SQG6o/94RinohLuB5noHSevg2Iqg2wXLDUn4lj2LWWo= -github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= github.com/micro/micro v1.8.0/go.mod h1:dF7nfyek86puqmlN1cEeyCos98rGzprwehRKJ4HMudE= github.com/micro/util v0.0.0-20181115195001-2d4f591dc538/go.mod h1:vxd7TGn28ynEMF4szG3PHTzgo3bx3FpfON9xpFsGc+g= @@ -827,7 +763,6 @@ github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00v github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI= github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -839,20 +774,16 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= -github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= 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.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= @@ -868,12 +799,9 @@ github.com/nats-io/jwt v0.2.12/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6Nr github.com/nats-io/nats-server/v2 v2.0.0/go.mod h1:RyVdsHHvY4B6c9pWG+uRLpZ0h0XsqiuKp2XCTurP5LI= github.com/nats-io/nats-server/v2 v2.0.2/go.mod h1:sk9mvTwGZiqHrkA12dw2r6LKmPYPkw15tB8haEsvxo8= github.com/nats-io/nats-streaming-server v0.15.1/go.mod h1:bJ1+2CS8MqvkGfr/NwnCF+Lw6aLnL3F5kenM8bZmdCw= -github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= -github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.4.5/go.mod h1:Ji7mK6gRZJSH1nc3ZJH6vi7zn/QnZhpR9Arm4iuzsUQ= github.com/nats-io/stan.go v0.5.0/go.mod h1:dYqB+vMN3C2F9pT1FRQpg9eHbjPj6mP0yYuyBNuXHZE= @@ -912,7 +840,6 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8 github.com/ory/graceful v0.1.1/go.mod h1:zqu70l95WrKHF4AZ6tXHvAqAvpY6M7g6ttaAVcMm7KU= github.com/ory/herodot v0.5.1/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= github.com/ory/herodot v0.6.0/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= -github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 h1:B95NIi2iuJ/zSuHByMvUQKa9lJH+6F3kxc+0BIjzzrU= github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12/go.mod h1:a0vgfecHsymehd3DuihIJxv5KMGJXpXVzD9IuKS7Vas= github.com/ory/x v0.0.49/go.mod h1:LVQf17Z8SK/y0H0ewDuIqJLDCjQ2eOIfQT5l0LH53ls= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= @@ -929,7 +856,6 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= @@ -937,7 +863,6 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77 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.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= -github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0= github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= github.com/prometheus/client_golang v0.0.0-20180328130430-f504d69affe1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -945,6 +870,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -984,7 +910,6 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5P github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= @@ -1043,13 +968,11 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -1064,6 +987,7 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= @@ -1085,14 +1009,11 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xakep666/mongo-migrate v0.1.0 h1:S8pnQJgcmnGI7LWUH7XJP4gOU9FO1MIB00Q3lGIDC64= github.com/xakep666/mongo-migrate v0.1.0/go.mod h1:8Nv3hSnx/kf3VG4njmsUoMzeNoftRT/zmypXlKD9ojY= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1119,13 +1040,9 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= gocloud.dev v0.15.0/go.mod h1:ShXCyJaGrJu9y/7a6+DSCyBb9MFGZ1P5wwPa0Wu6w34= @@ -1163,7 +1080,6 @@ golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= @@ -1226,7 +1142,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/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 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1237,7 +1152,6 @@ golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1299,13 +1213,12 @@ golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1396,7 +1309,6 @@ google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 h1:Ygq9/SRJX9+dU0WCIICM8RkWvDw03lvB77hrhJnpxfU= google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1409,7 +1321,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/DataDog/dd-trace-go.v1 v1.16.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -1427,9 +1338,7 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -1460,14 +1369,12 @@ gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcX gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20140626144623-14b3d72120e8/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= -gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= From 1ff4bdd14e43be8777e101696576e99cec83bf5e Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Mon, 11 Nov 2019 22:17:31 +0300 Subject: [PATCH 006/251] Don't request a scopes if requested only default scopes. --- pkg/api/oauth2.go | 14 ++++++++++++++ pkg/manager/oauth2.go | 25 ++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 49b410c..781d86d 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -123,6 +123,20 @@ func oauthConsent(ctx echo.Context) error { return ctx.HTML(http.StatusBadRequest, err.Message) } + if m.HasOnlyDefaultScopes(scopes) { + url, err := m.ConsentSubmit(ctx, &models.Oauth2ConsentSubmitForm{ + Challenge: form.Challenge, + Scope: scopes, + }) + + if err != nil { + ctx.Error(err.Err) + return ctx.HTML(http.StatusBadRequest, err.Message) + } + + return ctx.Redirect(http.StatusFound, url) + } + return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, "Challenge": form.Challenge, diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 8611b4c..a7f3512 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -15,9 +15,15 @@ import ( models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" "gopkg.in/tomb.v2" + "sort" "time" ) +const ( + scopeOffline = "offline" + scopeOpenId = "openid" +) + var ( loginRememberKey = "login_remember" clientIdSessionKey = "oauth_client_id" @@ -54,6 +60,9 @@ type OauthManagerInterface interface { // GetScopes returns a list of available scope for the application. GetScopes() ([]string, error) + // HasOnlyDefaultScopes returns true if the request contains only default scopes + HasOnlyDefaultScopes([]string) bool + // Introspect checks the token and returns its contents. // // Contains an access token's session data as specified by IETF RFC 7662, see: @@ -282,7 +291,7 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen } func (m *OauthManager) GetScopes() (scopes []string, err error) { - scopes = []string{"openid", "offline"} + scopes = []string{scopeOpenId, scopeOffline} /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ @@ -290,6 +299,20 @@ func (m *OauthManager) GetScopes() (scopes []string, err error) { return scopes, nil } +func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { + var s int + + if sort.SearchStrings(scopes, scopeOffline) == len(scopes) { + s++ + } + + if sort.SearchStrings(scopes, scopeOpenId) == len(scopes) { + s++ + } + + return s == len(scopes) +} + func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2IntrospectForm) (*models.Oauth2TokenIntrospection, *models.GeneralError) { app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(form.ClientID)) if err != nil { From 5e683de80ae14650eb8536310574d994aba1e068 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Mon, 11 Nov 2019 22:48:28 +0300 Subject: [PATCH 007/251] Don't request a scopes if requested only default scopes (fix) --- pkg/manager/oauth2.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index a7f3512..1d93878 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -302,6 +302,8 @@ func (m *OauthManager) GetScopes() (scopes []string, err error) { func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { var s int + sort.Strings(scopes) + if sort.SearchStrings(scopes, scopeOffline) == len(scopes) { s++ } From 3375980b7e8838af377769cc095cde0235497592 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Mon, 11 Nov 2019 23:39:03 +0300 Subject: [PATCH 008/251] Don't request a scopes if requested only default scopes (fix) --- pkg/api/oauth2.go | 3 +-- pkg/manager/oauth2.go | 30 ++++++++++++++++++++++-------- pkg/manager/oauth2_test.go | 5 ++--- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 781d86d..cd352ae 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -159,11 +159,10 @@ func oauthConsentSubmit(ctx echo.Context) error { url, err := m.ConsentSubmit(ctx, form) if err != nil { - scopes, _ := m.GetScopes() return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, "Challenge": form.Challenge, - "Scope": scopes, + "Scope": m.GetScopes(form.Scope), "Error": err.Error(), }) } diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 1d93878..8096d86 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -58,7 +58,7 @@ type OauthManagerInterface interface { ConsentSubmit(echo.Context, *models.Oauth2ConsentSubmitForm) (string, *models.GeneralError) // GetScopes returns a list of available scope for the application. - GetScopes() ([]string, error) + GetScopes([]string) []string // HasOnlyDefaultScopes returns true if the request contains only default scopes HasOnlyDefaultScopes([]string) bool @@ -235,12 +235,14 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm } func (m *OauthManager) Consent(ctx echo.Context, form *models.Oauth2ConsentForm) ([]string, *models.GeneralError) { - scopes, err := m.GetScopes() reqGCR, err := m.r.HydraAdminApi().GetConsentRequest(&admin.GetConsentRequestParams{Context: ctx.Request().Context(), Challenge: form.Challenge}) + if err != nil { - return scopes, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get consent challenge")} + return []string{}, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get consent challenge")} } + scopes := m.GetScopes(reqGCR.Payload.RequestedScope) + if err := m.session.Set(ctx, clientIdSessionKey, reqGCR.Payload.Client.ClientID); err != nil { return scopes, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error saving session")} } @@ -290,13 +292,25 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen return reqACR.Payload.RedirectTo, nil } -func (m *OauthManager) GetScopes() (scopes []string, err error) { - scopes = []string{scopeOpenId, scopeOffline} +func (m *OauthManager) GetScopes(requestedScopes []string) []string { + var scopes []string + + if len(requestedScopes) > 0 { + for _, scope := range requestedScopes { + if sort.SearchStrings(scopes, scope) < len(scopes) { + continue + } + + scopes = append(scopes, scope) + sort.Strings(scopes) + } + } + /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ - return scopes, nil + return scopes } func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { @@ -304,11 +318,11 @@ func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { sort.Strings(scopes) - if sort.SearchStrings(scopes, scopeOffline) == len(scopes) { + if sort.SearchStrings(scopes, scopeOffline) < len(scopes) { s++ } - if sort.SearchStrings(scopes, scopeOpenId) == len(scopes) { + if sort.SearchStrings(scopes, scopeOpenId) < len(scopes) { s++ } diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index d400a25..85a0729 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -567,9 +567,8 @@ func TestAuthReturnUrlToConsentRequest(t *testing.T) { func TestGetScopes(t *testing.T) { m := &OauthManager{} - scopes, err := m.GetScopes() - assert.Nil(t, err) - assert.Equal(t, []string{"openid", "offline"}, scopes) + scopes := []string{"openid", "offline"} + assert.Equal(t, scopes, m.GetScopes(append(scopes, "offline"))) } func TestConsentReturnErrorWithUnableToGetConsentRequest(t *testing.T) { From fa9bd694ca0d26d1a1af6dd5a2cb216da9ee2dd1 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Mon, 11 Nov 2019 23:50:56 +0300 Subject: [PATCH 009/251] Don't request a scopes if requested only default scopes (debug) --- pkg/manager/oauth2.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 8096d86..626b87d 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -14,6 +14,7 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" + "go.uber.org/zap" "gopkg.in/tomb.v2" "sort" "time" @@ -294,7 +295,7 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen func (m *OauthManager) GetScopes(requestedScopes []string) []string { var scopes []string - + zap.L().Error("[GetScopes] requested get scopes: ", zap.Strings("list", requestedScopes)) if len(requestedScopes) > 0 { for _, scope := range requestedScopes { if sort.SearchStrings(scopes, scope) < len(scopes) { @@ -309,15 +310,13 @@ func (m *OauthManager) GetScopes(requestedScopes []string) []string { /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ - + zap.L().Error("[GetScopes] get scopes: ", zap.Strings("list", scopes)) return scopes } func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { var s int - - sort.Strings(scopes) - + zap.L().Error("[HasOnlyDefaultScopes] scopes: ", zap.Strings("list", scopes)) if sort.SearchStrings(scopes, scopeOffline) < len(scopes) { s++ } @@ -325,7 +324,7 @@ func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { if sort.SearchStrings(scopes, scopeOpenId) < len(scopes) { s++ } - + zap.L().Error("[HasOnlyDefaultScopes] scopes find: ", zap.Int("len", s)) return s == len(scopes) } From b49c0ea69d1dde6e2e57a2c60efdbba4192ccce3 Mon Sep 17 00:00:00 2001 From: Vadim Sabirov Date: Tue, 12 Nov 2019 00:18:52 +0300 Subject: [PATCH 010/251] Auto accept scopes if it is empty --- pkg/api/oauth2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index cd352ae..244f7c6 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -123,7 +123,7 @@ func oauthConsent(ctx echo.Context) error { return ctx.HTML(http.StatusBadRequest, err.Message) } - if m.HasOnlyDefaultScopes(scopes) { + if len(scopes) == 0 || m.HasOnlyDefaultScopes(scopes) { url, err := m.ConsentSubmit(ctx, &models.Oauth2ConsentSubmitForm{ Challenge: form.Challenge, Scope: scopes, From f1b3a0415d60ee5f7ca1715c36c3eb560b24a06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC=20=D0=A1=D0=B0=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= Date: Tue, 12 Nov 2019 08:17:46 +0300 Subject: [PATCH 011/251] Remove debug info --- go.mod | 9 ++------- pkg/manager/oauth2.go | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 3890aef..fed82b9 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,14 @@ module github.com/ProtocolONE/auth1.protocol.one require ( - git.apache.org/thrift.git v0.12.0 // indirect github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb github.com/ProtocolONE/mfa-service v0.1.1 - github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect - github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect github.com/alicebob/miniredis v2.5.0+incompatible - github.com/apache/thrift v0.12.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/elliotchance/redismock v1.5.1 - github.com/fatih/structs v1.1.0 // indirect github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/go-openapi/runtime v0.19.0 github.com/go-openapi/strfmt v0.19.0 @@ -34,7 +29,6 @@ require ( github.com/labstack/gommon v0.2.8 github.com/micro/go-micro v1.8.0 github.com/micro/go-plugins v1.2.0 - github.com/openzipkin/zipkin-go v0.1.6 // indirect github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 github.com/pkg/errors v0.8.1 github.com/sirupsen/logrus v1.4.2 @@ -44,7 +38,6 @@ require ( github.com/xakep666/mongo-migrate v0.1.0 github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect go.uber.org/zap v1.10.0 - golang.org/x/build v0.0.0-20190314133821-5284462c4bec // indirect golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 gopkg.in/go-playground/validator.v9 v9.29.1 @@ -56,3 +49,5 @@ require ( ) replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.1 + +go 1.13 diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 626b87d..35538ff 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -14,7 +14,6 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" - "go.uber.org/zap" "gopkg.in/tomb.v2" "sort" "time" @@ -295,36 +294,38 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen func (m *OauthManager) GetScopes(requestedScopes []string) []string { var scopes []string - zap.L().Error("[GetScopes] requested get scopes: ", zap.Strings("list", requestedScopes)) + if len(requestedScopes) > 0 { for _, scope := range requestedScopes { + sort.Strings(scopes) + if sort.SearchStrings(scopes, scope) < len(scopes) { continue } scopes = append(scopes, scope) - sort.Strings(scopes) } } /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ - zap.L().Error("[GetScopes] get scopes: ", zap.Strings("list", scopes)) + return scopes } func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { - var s int - zap.L().Error("[HasOnlyDefaultScopes] scopes: ", zap.Strings("list", scopes)) - if sort.SearchStrings(scopes, scopeOffline) < len(scopes) { - s++ - } + s := 0 + defaultScopes := []string{scopeOffline, scopeOpenId} + + sort.Strings(scopes) - if sort.SearchStrings(scopes, scopeOpenId) < len(scopes) { - s++ + for _, scope := range defaultScopes { + if sort.SearchStrings(scopes, scope) < len(scopes) { + s++ + } } - zap.L().Error("[HasOnlyDefaultScopes] scopes find: ", zap.Int("len", s)) + return s == len(scopes) } From e4d6b20d0eb2ed3d9d5d3092a39221fb7824a787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC=20=D0=A1=D0=B0=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= Date: Tue, 12 Nov 2019 08:34:46 +0300 Subject: [PATCH 012/251] Add debug info --- pkg/manager/oauth2.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 35538ff..d9cc08f 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -14,6 +14,7 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" + "go.uber.org/zap" "gopkg.in/tomb.v2" "sort" "time" @@ -294,11 +295,13 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen func (m *OauthManager) GetScopes(requestedScopes []string) []string { var scopes []string - + zap.L().Error("[GetScopes] requested scopes: ", zap.Strings("list", requestedScopes)) if len(requestedScopes) > 0 { for _, scope := range requestedScopes { sort.Strings(scopes) - + zap.L().Error("[GetScopes] scopes: ", zap.Strings("scopes", scopes)) + zap.L().Error("[GetScopes] scope: ", zap.String("scope", scope)) + zap.L().Error("[GetScopes] search index: ", zap.Int("idx", sort.SearchStrings(scopes, scope))) if sort.SearchStrings(scopes, scope) < len(scopes) { continue } @@ -310,7 +313,7 @@ func (m *OauthManager) GetScopes(requestedScopes []string) []string { /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ - + zap.L().Error("[GetScopes] scopes result: ", zap.Strings("scopes", scopes)) return scopes } From 5c137753db5ad5d7e2437396a6a4a2fdbe3746eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC=20=D0=A1=D0=B0=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= Date: Tue, 12 Nov 2019 09:09:34 +0300 Subject: [PATCH 013/251] Remove debug info --- pkg/manager/oauth2.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index d9cc08f..9b60ca5 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -14,7 +14,6 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" - "go.uber.org/zap" "gopkg.in/tomb.v2" "sort" "time" @@ -295,25 +294,19 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen func (m *OauthManager) GetScopes(requestedScopes []string) []string { var scopes []string - zap.L().Error("[GetScopes] requested scopes: ", zap.Strings("list", requestedScopes)) - if len(requestedScopes) > 0 { - for _, scope := range requestedScopes { - sort.Strings(scopes) - zap.L().Error("[GetScopes] scopes: ", zap.Strings("scopes", scopes)) - zap.L().Error("[GetScopes] scope: ", zap.String("scope", scope)) - zap.L().Error("[GetScopes] search index: ", zap.Int("idx", sort.SearchStrings(scopes, scope))) - if sort.SearchStrings(scopes, scope) < len(scopes) { - continue - } + keys := make(map[string]bool, len(requestedScopes)) - scopes = append(scopes, scope) + for _, entry := range requestedScopes { + if _, value := keys[entry]; !value { + keys[entry] = true + scopes = append(scopes, entry) } } /*if err := m.loadRemoteScopes(scopes); err != nil { return nil, err }*/ - zap.L().Error("[GetScopes] scopes result: ", zap.Strings("scopes", scopes)) + return scopes } From 9d69ac15a3df7aa40155a6e503c1252b3b833ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D0=B4=D0=B8=D0=BC=20=D0=A1=D0=B0=D0=B1=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= Date: Mon, 18 Nov 2019 21:07:41 +0300 Subject: [PATCH 014/251] Update template for changing password, fix test --- go.sum | 96 +++++++ pkg/manager/change_password.go | 7 +- pkg/manager/oauth2_test.go | 2 +- public/templates/email/change_password.html | 294 ++++++++++++++++++++ 4 files changed, 397 insertions(+), 2 deletions(-) create mode 100644 public/templates/email/change_password.html diff --git a/go.sum b/go.sum index 130f908..ee537d9 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w= cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= @@ -71,13 +72,17 @@ github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXn github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb h1:xexVnYD1Eo/1+d2Mxnl/z82wkIYDEzcK8CZLNwDQyyk= github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb/go.mod h1:cAqWSwjCImM8kWcq/DjvE/ccyQdVpz3GafmV7pl0Ncc= github.com/ProtocolONE/go-micro-plugins v0.3.0/go.mod h1:/gvuHZoDRGfxS+ox0fHXuwwsTEVEHWRWKOhzbnozrZ8= +github.com/ProtocolONE/mfa-service v0.1.1 h1:+YB6I475E4SYP1HtaW6smusiBY/d2h8fc6i6TmQTKos= github.com/ProtocolONE/mfa-service v0.1.1/go.mod h1:8cwQ3Y+ub16gzN13OXVCgIKiN8Rp7czS+KfvJMFs5eU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.18/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= @@ -110,11 +115,13 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= 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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asim/go-awsxray v0.0.0-20161209120537-0d8a60b6e205/go.mod h1:frVmN4PtXUuL1EbZn0uL4PHSTKNKFnbMpBIhngqMuNQ= github.com/asim/go-bson v0.0.0-20160318195205-84522947cabd/go.mod h1:L59ZX7HuzTbNzFBt8g3SJkRraj+GBOgvLAfJYJUcQ5w= @@ -132,8 +139,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= @@ -174,10 +183,12 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/denisenkom/go-mssqldb v0.0.0-20180620032804-94c9c97e8c9f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +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/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= @@ -230,6 +241,7 @@ github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -241,6 +253,7 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I 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-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= 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= @@ -248,38 +261,51 @@ github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dT github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU= github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.0 h1:guf3T2lnCBKlODmERt4T9GtMWRpJOikgKGyIvi0xcb8= github.com/go-openapi/errors v0.19.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0 h1:KVRzjXpMzgdM4GEMDmDTnGcY5yBwGWreJwmmk4k35yU= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0 h1:oP2OUNdG1l2r5kYhrfVMXO54gWmzcfAwP/GFuHpNTkE= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8= github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.0 h1:SF5vyj6PBFM6D1cw2NJIFrlS8Su2YKk6ADPPjAH70Bw= github.com/go-openapi/validate v0.19.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.1+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redsync/redsync v1.3.0/go.mod h1:QClK/s99KRhfKdpxLTMsI5mSu43iLp0NfOneLPie+78= github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -490,13 +516,16 @@ github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 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= @@ -515,6 +544,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.2.2/go.mod h1:7FHVg6mFpFQrjeUZrm+BaD50N5jnDKm50uVPTpyYOmU= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= @@ -533,6 +563,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -542,9 +573,11 @@ github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +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.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -558,32 +591,41 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4c= github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= +github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= 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 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.0/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-discover v0.0.0-20190403160810-22221edb15cd/go.mod h1:ueUgD9BeIocT7QNuvxSyJyPAM9dfifBcaWmeybb67OY= github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= github.com/hashicorp/go-retryablehttp v0.0.0-20180531211321-3b087ef2d313/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= github.com/hashicorp/go-rootcerts v1.0.1/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 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= 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= @@ -594,6 +636,7 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 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.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20180906183839-65a6292f0157/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -602,6 +645,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= @@ -612,6 +656,7 @@ github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pN github.com/hashicorp/raft-boltdb v0.0.0-20190605210249-ef2e128ed477/go.mod h1:aUF6HQr8+t3FC/ZHAC+pZreUBhTaxumuu3L+d37uRxk= github.com/hashicorp/serf v0.8.1/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/vault v0.10.3/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= github.com/hashicorp/vault v1.1.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= @@ -627,6 +672,7 @@ github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwP github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= @@ -637,6 +683,7 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 h1:sHsPfNMAG70QAvKbddQ0uScZCHQoZsT5NykGRCeeeIs= github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -650,6 +697,7 @@ github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWx github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -670,6 +718,7 @@ github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.3.0 h1:IvRS4f2VcIQy6j4ORGIf9145T/AsUB+oY8LyvN8BXNM= github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -688,11 +737,17 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06NeXJqxT468ZqJhy0xPhV1969gVmN+OBL8W8= github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= +github.com/labstack/echo/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= +github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e h1:BsBWIgqA7BFb5sdQeFVQqXYL0P9ZwiNYvL3nywtEmnY= github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= +github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe h1:S7XSBlgc/eI2v47LkPPVa+infH3FuTS4tPJbqCtJovo= github.com/lestrrat-go/pdebug v0.0.0-20180220043849-39f9a71bcabe/go.mod h1:zvUY6gZZVL2nu7NM+/3b51Z/hxyFZCZxV0hvfZ3NJlg= github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -708,6 +763,7 @@ github.com/lyft/protoc-gen-validate v0.0.0-20180911180927-64fcb82c878e/go.mod h1 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= @@ -734,12 +790,14 @@ github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwm github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -748,14 +806,18 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod h1:Ylx55XGW4gjY7McWT0pgqU0aQquIOChDnYkOVbSuF/c= github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= +github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/go-log v0.0.0-20170512141327-cbfa9447f9b6/go.mod h1:QikSuviYcIE8V0CY4e0RRqVs3Oh8EuzX+qCEOnh9Qh8= github.com/micro/go-micro v0.22.1/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= +github.com/micro/go-micro v1.8.0 h1:4etDwf3DqP61cM0xrI+3OP+FlAsRUnM2rwBXFRTrl+Y= github.com/micro/go-micro v1.8.0/go.mod h1:RUJTXVb+qUnGx6jBK2yMCOzuB/xEKh/vdZc3uagM5TI= +github.com/micro/go-plugins v1.2.0 h1:/p9EzqJUiKkldzhANbu4hgKOaQufSBBwusQyhhvfjv8= github.com/micro/go-plugins v1.2.0/go.mod h1:N2UCiG7ExrTZ1N1dq1PF9bOgtuBOlUVEc86rfNGqxFQ= github.com/micro/go-rcache v0.0.0-20180418165751-a581a57b5133/go.mod h1:CBzgfnsCYHcyLg1qeTShF0iDErQmcLmSt+SdwjLkckI= github.com/micro/h2c v1.0.0/go.mod h1:54sOOQW/GRlHhH43vKwOhUb+kHaXhVxR0d3CJhn9alE= github.com/micro/mdns v0.0.0-20181201230301-9c3770d4057a/go.mod h1:SQG6o/94RinohLuB5noHSevg2Iqg2wXLDUn4lj2LWWo= +github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= github.com/micro/micro v1.8.0/go.mod h1:dF7nfyek86puqmlN1cEeyCos98rGzprwehRKJ4HMudE= github.com/micro/util v0.0.0-20181115195001-2d4f591dc538/go.mod h1:vxd7TGn28ynEMF4szG3PHTzgo3bx3FpfON9xpFsGc+g= @@ -763,6 +825,7 @@ github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00v github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI= github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -774,16 +837,20 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= 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.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= @@ -799,9 +866,12 @@ github.com/nats-io/jwt v0.2.12/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6Nr github.com/nats-io/nats-server/v2 v2.0.0/go.mod h1:RyVdsHHvY4B6c9pWG+uRLpZ0h0XsqiuKp2XCTurP5LI= github.com/nats-io/nats-server/v2 v2.0.2/go.mod h1:sk9mvTwGZiqHrkA12dw2r6LKmPYPkw15tB8haEsvxo8= github.com/nats-io/nats-streaming-server v0.15.1/go.mod h1:bJ1+2CS8MqvkGfr/NwnCF+Lw6aLnL3F5kenM8bZmdCw= +github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.4.5/go.mod h1:Ji7mK6gRZJSH1nc3ZJH6vi7zn/QnZhpR9Arm4iuzsUQ= github.com/nats-io/stan.go v0.5.0/go.mod h1:dYqB+vMN3C2F9pT1FRQpg9eHbjPj6mP0yYuyBNuXHZE= @@ -840,6 +910,7 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8 github.com/ory/graceful v0.1.1/go.mod h1:zqu70l95WrKHF4AZ6tXHvAqAvpY6M7g6ttaAVcMm7KU= github.com/ory/herodot v0.5.1/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= github.com/ory/herodot v0.6.0/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow= +github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 h1:B95NIi2iuJ/zSuHByMvUQKa9lJH+6F3kxc+0BIjzzrU= github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12/go.mod h1:a0vgfecHsymehd3DuihIJxv5KMGJXpXVzD9IuKS7Vas= github.com/ory/x v0.0.49/go.mod h1:LVQf17Z8SK/y0H0ewDuIqJLDCjQ2eOIfQT5l0LH53ls= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= @@ -856,13 +927,16 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= +github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0= github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= github.com/prometheus/client_golang v0.0.0-20180328130430-f504d69affe1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -910,6 +984,7 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5P github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M= @@ -968,11 +1043,13 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -982,11 +1059,13 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 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.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -1009,11 +1088,14 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xakep666/mongo-migrate v0.1.0 h1:S8pnQJgcmnGI7LWUH7XJP4gOU9FO1MIB00Q3lGIDC64= github.com/xakep666/mongo-migrate v0.1.0/go.mod h1:8Nv3hSnx/kf3VG4njmsUoMzeNoftRT/zmypXlKD9ojY= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1040,9 +1122,12 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= gocloud.dev v0.15.0/go.mod h1:ShXCyJaGrJu9y/7a6+DSCyBb9MFGZ1P5wwPa0Wu6w34= @@ -1080,6 +1165,7 @@ golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= @@ -1142,6 +1228,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/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 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1152,6 +1239,7 @@ golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1214,11 +1302,13 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1309,6 +1399,7 @@ google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610 h1:Ygq9/SRJX9+dU0WCIICM8RkWvDw03lvB77hrhJnpxfU= google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1321,6 +1412,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/DataDog/dd-trace-go.v1 v1.16.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -1338,7 +1430,9 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -1369,12 +1463,14 @@ gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcX gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20140626144623-14b3d72120e8/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= +gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= diff --git a/pkg/manager/change_password.go b/pkg/manager/change_password.go index 220d353..8f0147f 100644 --- a/pkg/manager/change_password.go +++ b/pkg/manager/change_password.go @@ -9,6 +9,8 @@ import ( "github.com/ProtocolONE/auth1.protocol.one/pkg/validator" "github.com/globalsign/mgo/bson" "github.com/pkg/errors" + "io/ioutil" + "strings" ) // ChangePasswordManagerInterface describes of methods for the manager. @@ -71,7 +73,10 @@ func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordS return &models.GeneralError{Code: "common", Message: models.ErrorUnableCreateOttSettings, Err: errors.Wrap(err, "Unable to create OneTimeToken")} } - if err := m.r.Mailer().Send(form.Email, "Change password token", fmt.Sprintf("Token: %s", token.Token)); err != nil { + b, err := ioutil.ReadFile("./public/templates/email/change_password.html") + body := strings.ReplaceAll(string(b), "{{code}}", token.Token) + fmt.Println(body) + if err := m.r.Mailer().Send(form.Email, "Change password token", body); err != nil { return &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to send mail with change password token")} } diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 85a0729..5caedf4 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -609,7 +609,7 @@ func TestConsentReturnScopes(t *testing.T) { s := &mocks.SessionService{} r := &mocks.InternalRegistry{} - h.On("GetConsentRequest", mock.Anything).Return(&admin.GetConsentRequestOK{Payload: &models2.ConsentRequest{Client: &models2.Client{ClientID: bson.NewObjectId().Hex()}}}, nil) + h.On("GetConsentRequest", mock.Anything).Return(&admin.GetConsentRequestOK{Payload: &models2.ConsentRequest{Client: &models2.Client{ClientID: bson.NewObjectId().Hex()}, RequestedScope: []string{"openid", "offline"}}}, nil) s.On("Set", mock.Anything, clientIdSessionKey, mock.Anything).Return(nil) r.On("HydraAdminApi").Return(h) diff --git a/public/templates/email/change_password.html b/public/templates/email/change_password.html new file mode 100644 index 0000000..0cb10ac --- /dev/null +++ b/public/templates/email/change_password.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + From 4e1779cc906b59cddec44be7ee66042ff75974f1 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Sat, 1 Feb 2020 00:49:55 +0300 Subject: [PATCH 015/251] fix: bug in HasOnlyDefaultScopes --- go.mod | 2 ++ go.sum | 11 ++++------- pkg/manager/oauth2.go | 15 +++++++++++++++ pkg/manager/oauth2_test.go | 16 +++++++++++++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index fed82b9..44c564a 100644 --- a/go.mod +++ b/go.mod @@ -50,4 +50,6 @@ require ( replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.1 +replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.0 + go 1.13 diff --git a/go.sum b/go.sum index ee537d9..9e9ce58 100644 --- a/go.sum +++ b/go.sum @@ -138,6 +138,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= @@ -496,10 +497,7 @@ github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhD github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/protobuf v0.0.0-20190410021324-65acae22fc9/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20181116215533-9bd4a3295021/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20190312205958-5a2505f3dbf0/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= @@ -672,7 +670,6 @@ github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwP github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= @@ -725,17 +722,18 @@ github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +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/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06NeXJqxT468ZqJhy0xPhV1969gVmN+OBL8W8= github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= @@ -1313,7 +1311,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 9b60ca5..bf5d320 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -311,6 +311,10 @@ func (m *OauthManager) GetScopes(requestedScopes []string) []string { } func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { + return hasOnlyDefaultScopes(scopes) +} + +func oldHasOnlyDefaultScopes(scopes []string) bool { s := 0 defaultScopes := []string{scopeOffline, scopeOpenId} @@ -325,6 +329,17 @@ func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { return s == len(scopes) } +func hasOnlyDefaultScopes(scopes []string) bool { + for _, s := range scopes { + switch s { + case scopeOffline, scopeOpenId: + default: + return false + } + } + return true +} + func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2IntrospectForm) (*models.Oauth2TokenIntrospection, *models.GeneralError) { app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(form.ClientID)) if err != nil { diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 5caedf4..978fc89 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -1,6 +1,8 @@ package manager import ( + "testing" + "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/mocks" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -11,7 +13,6 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "testing" ) func TestOauthManager(t *testing.T) { @@ -1306,3 +1307,16 @@ func TestLoadRemoteScopesReturnNil(t *testing.T) { err := m.loadRemoteScopes([]string{"scope1"}) assert.Nil(t, err) } + +func TestHasOnlyDefaultScopes(t *testing.T) { + assert.True(t, oldHasOnlyDefaultScopes([]string{})) + assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOpenId})) // fail + assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOffline})) + assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline})) + assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOffline, scopeOpenId})) + assert.False(t, oldHasOnlyDefaultScopes([]string{"other"})) + assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, "other"})) // fail + assert.False(t, oldHasOnlyDefaultScopes([]string{"other", scopeOffline})) // fail + assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline, "other"})) + assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOffline, "other", scopeOpenId})) +} From 3c68a70057d7285737942a1035a7bf88af84d161 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Sat, 1 Feb 2020 00:52:26 +0300 Subject: [PATCH 016/251] fix: remove old impl HasOnlyDefaultScopes --- pkg/manager/oauth2.go | 16 ---------------- pkg/manager/oauth2_test.go | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index bf5d320..e31cc29 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -15,7 +15,6 @@ import ( models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" "gopkg.in/tomb.v2" - "sort" "time" ) @@ -314,21 +313,6 @@ func (m *OauthManager) HasOnlyDefaultScopes(scopes []string) bool { return hasOnlyDefaultScopes(scopes) } -func oldHasOnlyDefaultScopes(scopes []string) bool { - s := 0 - defaultScopes := []string{scopeOffline, scopeOpenId} - - sort.Strings(scopes) - - for _, scope := range defaultScopes { - if sort.SearchStrings(scopes, scope) < len(scopes) { - s++ - } - } - - return s == len(scopes) -} - func hasOnlyDefaultScopes(scopes []string) bool { for _, s := range scopes { switch s { diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 978fc89..ea7f248 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -1309,14 +1309,14 @@ func TestLoadRemoteScopesReturnNil(t *testing.T) { } func TestHasOnlyDefaultScopes(t *testing.T) { - assert.True(t, oldHasOnlyDefaultScopes([]string{})) - assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOpenId})) // fail - assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOffline})) - assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline})) - assert.True(t, oldHasOnlyDefaultScopes([]string{scopeOffline, scopeOpenId})) - assert.False(t, oldHasOnlyDefaultScopes([]string{"other"})) - assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, "other"})) // fail - assert.False(t, oldHasOnlyDefaultScopes([]string{"other", scopeOffline})) // fail - assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline, "other"})) - assert.False(t, oldHasOnlyDefaultScopes([]string{scopeOffline, "other", scopeOpenId})) + assert.True(t, hasOnlyDefaultScopes([]string{})) + assert.True(t, hasOnlyDefaultScopes([]string{scopeOpenId})) // fail + assert.True(t, hasOnlyDefaultScopes([]string{scopeOffline})) + assert.True(t, hasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline})) + assert.True(t, hasOnlyDefaultScopes([]string{scopeOffline, scopeOpenId})) + assert.False(t, hasOnlyDefaultScopes([]string{"other"})) + assert.False(t, hasOnlyDefaultScopes([]string{scopeOpenId, "other"})) // fail + assert.False(t, hasOnlyDefaultScopes([]string{"other", scopeOffline})) // fail + assert.False(t, hasOnlyDefaultScopes([]string{scopeOpenId, scopeOffline, "other"})) + assert.False(t, hasOnlyDefaultScopes([]string{scopeOffline, "other", scopeOpenId})) } From d16991fd61c8931e79768482b6849b586a693770 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Sat, 1 Feb 2020 02:43:27 +0300 Subject: [PATCH 017/251] feat(api): checks for username availability --- pkg/api/signup.go | 41 +++++++++++++++++++++++++++++++ pkg/mocks/UserServiceInterface.go | 30 +++++++++++++++++++--- pkg/service/user.go | 9 +++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 pkg/api/signup.go diff --git a/pkg/api/signup.go b/pkg/api/signup.go new file mode 100644 index 0000000..627acc5 --- /dev/null +++ b/pkg/api/signup.go @@ -0,0 +1,41 @@ +package api + +import ( + "net/http" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/ProtocolONE/auth1.protocol.one/pkg/service" + "github.com/labstack/echo/v4" +) + +func InitSignup(cfg *Server) error { + cfg.Echo.POST("/signup/checkUsername", checkUsername) + + return nil +} + +func checkUsername(ctx echo.Context) error { + var r struct { + Username string `json:"username"` + } + + if err := ctx.Bind(&r); err != nil { + ctx.Error(err) + return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) + } + + db := ctx.Get("database").(database.MgoSession) + users := service.NewUserService(db) + ok, err := users.IsUsernameFree(r.Username) + if err != nil { + ctx.Error(err) + return ctx.JSON(http.StatusInternalServerError, map[string]interface{}{}) + } + + if ok { + return ctx.JSON(http.StatusOK, map[string]interface{}{}) + } + + return ctx.JSON(http.StatusForbidden, map[string]interface{}{}) +} diff --git a/pkg/mocks/UserServiceInterface.go b/pkg/mocks/UserServiceInterface.go index 45d0ca3..472e557 100644 --- a/pkg/mocks/UserServiceInterface.go +++ b/pkg/mocks/UserServiceInterface.go @@ -2,9 +2,12 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // UserServiceInterface is an autogenerated mock type for the UserServiceInterface type type UserServiceInterface struct { @@ -48,6 +51,27 @@ func (_m *UserServiceInterface) Get(_a0 bson.ObjectId) (*models.User, error) { return r0, r1 } +// IsUsernameFree provides a mock function with given fields: username +func (_m *UserServiceInterface) IsUsernameFree(username string) (bool, error) { + ret := _m.Called(username) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(username) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(username) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Update provides a mock function with given fields: _a0 func (_m *UserServiceInterface) Update(_a0 *models.User) error { ret := _m.Called(_a0) diff --git a/pkg/service/user.go b/pkg/service/user.go index 50d9167..e767d70 100644 --- a/pkg/service/user.go +++ b/pkg/service/user.go @@ -17,6 +17,9 @@ type UserServiceInterface interface { // Get return the user by id. Get(bson.ObjectId) (*models.User, error) + + // IsUsernameFree checks if username is available for signup + IsUsernameFree(username string) (bool, error) } // UserService is the user service. @@ -55,3 +58,9 @@ func (us UserService) Get(id bson.ObjectId) (*models.User, error) { return u, nil } + +func (us UserService) IsUsernameFree(username string) (bool, error) { + // TODO: Optimize for case when multiple same username allowed + n, err := us.db.C(database.TableUser).Find(bson.M{"username": username}).Count() + return n == 0, err +} From a49427f7409e82abfb770c066c2291bcb50928e7 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 4 Feb 2020 23:30:00 +0300 Subject: [PATCH 018/251] support unique usernames --- go.sum | 4 ++ pkg/api/oauth2.go | 29 ++++++++++++- pkg/api/signup.go | 41 ------------------ ...0200204_01_create_username_unique_index.go | 43 +++++++++++++++++++ pkg/manager/manage.go | 5 ++- pkg/manager/oauth2.go | 40 +++++++++++++++++ pkg/mocks/UserServiceInterface.go | 14 +++--- pkg/models/application.go | 6 ++- pkg/models/error.go | 1 + pkg/models/manage.go | 1 + pkg/models/oauth2.go | 4 ++ pkg/models/user.go | 6 ++- pkg/service/user.go | 6 +-- 13 files changed, 145 insertions(+), 55 deletions(-) delete mode 100644 pkg/api/signup.go create mode 100644 pkg/database/migrations/20200204_01_create_username_unique_index.go diff --git a/go.sum b/go.sum index 9e9ce58..535c1e4 100644 --- a/go.sum +++ b/go.sum @@ -670,6 +670,7 @@ github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwP github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= @@ -829,6 +830,7 @@ github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v0.0.0-20160804032330-cdac8253d00f/go.mod h1:eOsF2yLPlBBJPvD+nhl5QMTBSOBbOph6N7j/IDUw7PY= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= @@ -1379,6 +1381,7 @@ google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 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.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1414,6 +1417,7 @@ google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac gopkg.in/DataDog/dd-trace-go.v1 v1.16.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 244f7c6..8b942b3 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -2,12 +2,13 @@ package api import ( "fmt" + "net/http" + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/labstack/echo/v4" - "net/http" ) func InitOauth2(cfg *Server) error { @@ -25,6 +26,7 @@ func InitOauth2(cfg *Server) error { g.GET("/consent", oauthConsent) g.POST("/consent", oauthConsentSubmit) g.POST("/signup", oauthSignUp) + g.POST("/checkUsername", oauthCheckUsername) g.POST("/introspect", oauthIntrospect) g.GET("/callback", oauthCallback) g.GET("/logout", oauthLogout) @@ -214,6 +216,31 @@ func oauthSignUp(ctx echo.Context) error { return ctx.JSON(http.StatusOK, map[string]interface{}{"url": url}) } +func oauthCheckUsername(ctx echo.Context) error { + var r struct { + Username string `json:"username"` + } + + if err := ctx.Bind(&r); err != nil { + ctx.Error(err) + return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) + } + + m := ctx.Get("oauth_manager").(*manager.OauthManager) + + ok, err := m.IsUsernameFree(ctx, r.Username) + if err != nil { + ctx.Error(err) + return ctx.JSON(http.StatusInternalServerError, err) + } + + if ok { + return ctx.JSON(http.StatusOK, map[string]interface{}{}) + } + + return ctx.JSON(http.StatusForbidden, map[string]interface{}{}) +} + func oauthCallback(ctx echo.Context) error { form := new(models.Oauth2CallBackForm) m := ctx.Get("oauth_manager").(*manager.OauthManager) diff --git a/pkg/api/signup.go b/pkg/api/signup.go deleted file mode 100644 index 627acc5..0000000 --- a/pkg/api/signup.go +++ /dev/null @@ -1,41 +0,0 @@ -package api - -import ( - "net/http" - - "github.com/ProtocolONE/auth1.protocol.one/pkg/database" - "github.com/ProtocolONE/auth1.protocol.one/pkg/models" - "github.com/ProtocolONE/auth1.protocol.one/pkg/service" - "github.com/labstack/echo/v4" -) - -func InitSignup(cfg *Server) error { - cfg.Echo.POST("/signup/checkUsername", checkUsername) - - return nil -} - -func checkUsername(ctx echo.Context) error { - var r struct { - Username string `json:"username"` - } - - if err := ctx.Bind(&r); err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) - } - - db := ctx.Get("database").(database.MgoSession) - users := service.NewUserService(db) - ok, err := users.IsUsernameFree(r.Username) - if err != nil { - ctx.Error(err) - return ctx.JSON(http.StatusInternalServerError, map[string]interface{}{}) - } - - if ok { - return ctx.JSON(http.StatusOK, map[string]interface{}{}) - } - - return ctx.JSON(http.StatusForbidden, map[string]interface{}{}) -} diff --git a/pkg/database/migrations/20200204_01_create_username_unique_index.go b/pkg/database/migrations/20200204_01_create_username_unique_index.go new file mode 100644 index 0000000..d89613f --- /dev/null +++ b/pkg/database/migrations/20200204_01_create_username_unique_index.go @@ -0,0 +1,43 @@ +package migrations + +import ( + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" + "github.com/globalsign/mgo" + "github.com/pkg/errors" + "github.com/xakep666/mongo-migrate" + "github.com/globalsign/mgo/bson" +) + +func init() { + err := migrate.Register( + func(db *mgo.Database) error { + var err error + + db.C(database.TableUser).EnsureIndex(mgo.Index{ + Name: "Idx-Username-AppId", + Key: []string{"username", "app_id"}, + PartialFilter: bson.M{"uniq_username": true}, + Unique: true, + Background: true, + Sparse: false, + }) + + if err != nil { + return errors.Wrapf(err, "Ensure user identity collection `Idx-Username-AppId` index failed") + } + + return nil + }, + func(db *mgo.Database) error { + if err := db.C(database.TableUserIdentity).DropIndex("username", "app_id"); err != nil { + return errors.Wrapf(err, "Drop user identity collection `Idx-AppId-ExternalId-Connection` index failed") + } + + return nil + }, + ) + + if err != nil { + return + } +} diff --git a/pkg/manager/manage.go b/pkg/manager/manage.go index b409e67..780f090 100644 --- a/pkg/manager/manage.go +++ b/pkg/manager/manage.go @@ -2,6 +2,8 @@ package manager import ( "fmt" + "time" + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -11,7 +13,6 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" hydra_models "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" - "time" ) type ManageManager struct { @@ -96,6 +97,7 @@ func (m *ManageManager) CreateApplication(ctx echo.Context, form *models.Applica AuthSecret: helper.GetRandString(64), AuthRedirectUrls: form.Application.AuthRedirectUrls, HasSharedUsers: form.Application.HasSharedUsers, + UniqueUsernames: form.Application.UniqueUsernames, PasswordSettings: &models.PasswordSettings{ BcryptCost: models.PasswordBcryptCostDefault, Min: models.PasswordMinDefault, @@ -167,6 +169,7 @@ func (m *ManageManager) UpdateApplication(ctx echo.Context, id string, form *mod a.UpdatedAt = time.Now() a.AuthRedirectUrls = form.Application.AuthRedirectUrls a.HasSharedUsers = form.Application.HasSharedUsers + a.UniqueUsernames = form.Application.UniqueUsernames if err := m.r.ApplicationService().Update(a); err != nil { return nil, &models.GeneralError{Message: "Unable to update application", Err: errors.Wrap(err, "Unable to update application")} diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index e31cc29..2ecba61 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -73,6 +73,9 @@ type OauthManagerInterface interface { // After successful registration, the URL for the redirect will be returned to pass the agreement consent process. SignUp(echo.Context, *models.Oauth2SignUpForm) (string, *models.GeneralError) + // IsUsernameFree checks if username is available for signup + IsUsernameFree(ctx echo.Context, username string) (bool, error) + // CallBack verifies the result of oauth2 authorization. // // The method is implemented for applications that do not have their own backend, @@ -347,6 +350,29 @@ func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2Introspec return token, nil } +func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, error) { + clientId, err := m.session.Get(ctx, clientIdSessionKey) + if err != nil { + return false, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get session")} + } + + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientId.(string))) + if err != nil { + return false, &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} + } + + if app.UniqueUsernames == false { + return true, nil + } + + ok, err := m.userService.IsUsernameFree(username, app.ID) + if err != nil { + return false, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "unable check username availability")} + } + + return ok, nil +} + func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) (string, *models.GeneralError) { if err := m.session.Set(ctx, loginRememberKey, form.Remember); err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error saving session")} @@ -361,6 +387,18 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( if err != nil { return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} } + + if app.UniqueUsernames { + + free, err := m.userService.IsUsernameFree(form.Username, app.ID) + if err != nil { + return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to check username availability")} + } + if !free { + return "", &models.GeneralError{Code: "username_taken", Message: models.ErrorUsernameTaken, Err: errors.New(models.ErrorUsernameTaken)} + } + } + if false == validator.IsPasswordValid(app, form.Password) { return "", &models.GeneralError{Code: "password", Message: models.ErrorPasswordIncorrect, Err: errors.New(models.ErrorPasswordIncorrect)} } @@ -398,6 +436,8 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( user := &models.User{ ID: bson.NewObjectId(), AppID: app.ID, + Username: form.Username, + UniqUsername: app.UniqueUsernames, Email: form.Email, EmailVerified: false, Blocked: false, diff --git a/pkg/mocks/UserServiceInterface.go b/pkg/mocks/UserServiceInterface.go index 472e557..bf4725f 100644 --- a/pkg/mocks/UserServiceInterface.go +++ b/pkg/mocks/UserServiceInterface.go @@ -51,20 +51,20 @@ func (_m *UserServiceInterface) Get(_a0 bson.ObjectId) (*models.User, error) { return r0, r1 } -// IsUsernameFree provides a mock function with given fields: username -func (_m *UserServiceInterface) IsUsernameFree(username string) (bool, error) { - ret := _m.Called(username) +// IsUsernameFree provides a mock function with given fields: username, appID +func (_m *UserServiceInterface) IsUsernameFree(username string, appID string) (bool, error) { + ret := _m.Called(username, appID) var r0 bool - if rf, ok := ret.Get(0).(func(string) bool); ok { - r0 = rf(username) + if rf, ok := ret.Get(0).(func(string, string) bool); ok { + r0 = rf(username, appID) } else { r0 = ret.Get(0).(bool) } var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(username) + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(username, appID) } else { r1 = ret.Error(1) } diff --git a/pkg/models/application.go b/pkg/models/application.go index 68df8b5..00aad5c 100644 --- a/pkg/models/application.go +++ b/pkg/models/application.go @@ -1,9 +1,10 @@ package models import ( + "time" + "github.com/globalsign/mgo/bson" "go.uber.org/zap/zapcore" - "time" ) var ( @@ -66,6 +67,9 @@ type Application struct { // If this option is set, then users from other applications (in space) will be able to log in to this application. HasSharedUsers bool `bson:"has_shared_users" json:"has_shared_users"` + // UniqueUsernames determines whether app users must have unique usernames + UniqueUsernames bool `bson:"unique_usernames" json:"unique_usernames"` + // PasswordSettings contains settings for valid password criteria. PasswordSettings *PasswordSettings `bson:"password_settings" json:"password_settings"` diff --git a/pkg/models/error.go b/pkg/models/error.go index e9cf4e7..e0be8cb 100644 --- a/pkg/models/error.go +++ b/pkg/models/error.go @@ -33,6 +33,7 @@ var ( ErrorLoginChallenge = "Invalid login challenge" ErrorAppIdIncorrect = "Application ID is incorrect" ErrorMfaClientRemove = "Unable to remove MFA" + ErrorUsernameTaken = "Username already taken" ) // ErrorInterface defines basic methods for application errors. diff --git a/pkg/models/manage.go b/pkg/models/manage.go index a40b335..3f1e2bd 100644 --- a/pkg/models/manage.go +++ b/pkg/models/manage.go @@ -23,6 +23,7 @@ type ApplicationFormApp struct { IsActive bool `bson:"is_active" json:"is_active"` AuthRedirectUrls []string `bson:"auth_redirect_urls" json:"auth_redirect_urls" validate:"required"` HasSharedUsers bool `bson:"has_shared_users" json:"has_shared_users"` + UniqueUsernames bool `bson:"unique_usernames" json:"unique_usernames"` } func (a *ApplicationFormApp) MarshalLogObject(enc zapcore.ObjectEncoder) error { diff --git a/pkg/models/oauth2.go b/pkg/models/oauth2.go index aa202b0..4c61f78 100644 --- a/pkg/models/oauth2.go +++ b/pkg/models/oauth2.go @@ -156,6 +156,9 @@ type Oauth2SignUpForm struct { // Challenge is the code of the oauth2 login challenge. This code to generates of the Hydra service. Challenge string `query:"challenge" form:"challenge" validate:"required"` + // Username represent user nickname, optional. + Username string `query:"username" form:"username"` + // Email is the email address of user for the registration. Email string `query:"email" form:"email" validate:"required"` @@ -168,6 +171,7 @@ type Oauth2SignUpForm struct { func (a *Oauth2SignUpForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { enc.AddString("Challenge", a.Challenge) + enc.AddString("Username", a.Username) enc.AddString("Email", a.Email) enc.AddString("Password", "[HIDDEN]") diff --git a/pkg/models/user.go b/pkg/models/user.go index 6c80840..9da0f68 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -1,9 +1,10 @@ package models import ( + "time" + "github.com/globalsign/mgo/bson" "go.uber.org/zap/zapcore" - "time" ) // User describes a table for storing the basic properties of the user. @@ -29,6 +30,9 @@ type User struct { // Username is the nickname of the user. Username string `bson:"username" json:"username"` + // UniqUsername is index flag that username must be unique within app. + UniqUsername bool `bson:"uniq_username" json:"-"` + // Name is the name of the user. Contains first anf last name. Name string `bson:"name" json:"name"` diff --git a/pkg/service/user.go b/pkg/service/user.go index e767d70..edcba6e 100644 --- a/pkg/service/user.go +++ b/pkg/service/user.go @@ -19,7 +19,7 @@ type UserServiceInterface interface { Get(bson.ObjectId) (*models.User, error) // IsUsernameFree checks if username is available for signup - IsUsernameFree(username string) (bool, error) + IsUsernameFree(username string, appID bson.ObjectId) (bool, error) } // UserService is the user service. @@ -59,8 +59,8 @@ func (us UserService) Get(id bson.ObjectId) (*models.User, error) { return u, nil } -func (us UserService) IsUsernameFree(username string) (bool, error) { +func (us UserService) IsUsernameFree(username string, appID bson.ObjectId) (bool, error) { // TODO: Optimize for case when multiple same username allowed - n, err := us.db.C(database.TableUser).Find(bson.M{"username": username}).Count() + n, err := us.db.C(database.TableUser).Find(bson.M{"username": username, "app_id": appID}).Count() return n == 0, err } From a8a42ea5424a7cd660573b46312deb9c4874f66d Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 5 Feb 2020 07:49:32 +0300 Subject: [PATCH 019/251] regenerate user service mock --- pkg/mocks/UserServiceInterface.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/mocks/UserServiceInterface.go b/pkg/mocks/UserServiceInterface.go index bf4725f..d7f3ffc 100644 --- a/pkg/mocks/UserServiceInterface.go +++ b/pkg/mocks/UserServiceInterface.go @@ -52,18 +52,18 @@ func (_m *UserServiceInterface) Get(_a0 bson.ObjectId) (*models.User, error) { } // IsUsernameFree provides a mock function with given fields: username, appID -func (_m *UserServiceInterface) IsUsernameFree(username string, appID string) (bool, error) { +func (_m *UserServiceInterface) IsUsernameFree(username string, appID bson.ObjectId) (bool, error) { ret := _m.Called(username, appID) var r0 bool - if rf, ok := ret.Get(0).(func(string, string) bool); ok { + if rf, ok := ret.Get(0).(func(string, bson.ObjectId) bool); ok { r0 = rf(username, appID) } else { r0 = ret.Get(0).(bool) } var r1 error - if rf, ok := ret.Get(1).(func(string, string) error); ok { + if rf, ok := ret.Get(1).(func(string, bson.ObjectId) error); ok { r1 = rf(username, appID) } else { r1 = ret.Error(1) From a9a447b5b46632d590a91a70b430191ef44615ed Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 5 Feb 2020 08:07:24 +0300 Subject: [PATCH 020/251] integration tests and fmt --- .travis.yml | 2 +- .../20200204_01_create_username_unique_index.go | 12 ++++++------ pkg/manager/mfa.go | 4 ++-- pkg/manager/mfa_test.go | 4 +--- pkg/manager/oauth2.go | 6 +++--- pkg/persist/redis/watcher_test.go | 7 +++++-- pkg/service/mfa.go | 2 +- pkg/service/one_time_token_test.go | 5 ++++- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2cec13f..b5de187 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ jobs: before_script: - mongo auth-one --eval 'db.createUser({user:"travis",pwd:"test",roles:["readWrite"]});' script: - - go test ./... -coverprofile=coverage.out -covermode=atomic -p=1 + - go test --tags=integration ./... -coverprofile=coverage.out -covermode=atomic -p=1 after_success: - bash <(curl -s https://codecov.io/bash) - stage: deploy diff --git a/pkg/database/migrations/20200204_01_create_username_unique_index.go b/pkg/database/migrations/20200204_01_create_username_unique_index.go index d89613f..652e837 100644 --- a/pkg/database/migrations/20200204_01_create_username_unique_index.go +++ b/pkg/database/migrations/20200204_01_create_username_unique_index.go @@ -3,9 +3,9 @@ package migrations import ( "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/globalsign/mgo" + "github.com/globalsign/mgo/bson" "github.com/pkg/errors" "github.com/xakep666/mongo-migrate" - "github.com/globalsign/mgo/bson" ) func init() { @@ -14,12 +14,12 @@ func init() { var err error db.C(database.TableUser).EnsureIndex(mgo.Index{ - Name: "Idx-Username-AppId", - Key: []string{"username", "app_id"}, + Name: "Idx-Username-AppId", + Key: []string{"username", "app_id"}, PartialFilter: bson.M{"uniq_username": true}, - Unique: true, - Background: true, - Sparse: false, + Unique: true, + Background: true, + Sparse: false, }) if err != nil { diff --git a/pkg/manager/mfa.go b/pkg/manager/mfa.go index 4dd6306..d4f8556 100644 --- a/pkg/manager/mfa.go +++ b/pkg/manager/mfa.go @@ -78,7 +78,7 @@ func (m *MFAManager) MFARemove(ctx echo.Context, form *models.MfaRemoveForm) *mo return &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to validate bearer token")} } - err = m.mfaService.RemoveUserProvider(&models.MfaUserProvider{ + err = m.mfaService.RemoveUserProvider(&models.MfaUserProvider{ UserID: c.UserId, ProviderID: p.ID, }) @@ -87,7 +87,7 @@ func (m *MFAManager) MFARemove(ctx echo.Context, form *models.MfaRemoveForm) *mo return &models.GeneralError{Code: "common", Message: models.ErrorMfaClientRemove, Err: errors.Wrap(err, "Unable to remove user provider")} } - return nil + return nil } func (m *MFAManager) MFAList(ctx echo.Context, form *models.MfaListForm) ([]*models.MfaProvider, *models.GeneralError) { diff --git a/pkg/manager/mfa_test.go b/pkg/manager/mfa_test.go index 916dc13..dd6af9a 100644 --- a/pkg/manager/mfa_test.go +++ b/pkg/manager/mfa_test.go @@ -299,7 +299,6 @@ func TestMFAManagerError_MFAList(t *testing.T) { assert.Equal(t, models.ErrorAppIdIncorrect, err.Message) } - func TestMFAManagerSuccess_MFAList(t *testing.T) { mfa := &mocks.MfaServiceInterface{} r := &mocks.InternalRegistry{} @@ -370,7 +369,7 @@ func TestMFAManagerErrorWithoutHeaders_MFARemove(t *testing.T) { r := &mocks.InternalRegistry{} id := bson.NewObjectId() - app.On("Get", mock.Anything).Return(&models.Application{ID: id }, nil) + app.On("Get", mock.Anything).Return(&models.Application{ID: id}, nil) mfa.On("Get", mock.Anything).Return(&models.MfaProvider{ID: bson.NewObjectId(), AppID: id}, nil) mfa.On("RemoveUserProvider", mock.Anything).Return(nil) r.On("ApplicationService").Return(app) @@ -434,4 +433,3 @@ func TestMFAManagerSuccess_MFARemove(t *testing.T) { err := m.MFARemove(getContext(map[string]interface{}{"headers": headers}), &models.MfaRemoveForm{ClientId: bson.NewObjectId().Hex(), ProviderId: bson.NewObjectId().Hex()}) assert.Nil(t, err) } - diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 2ecba61..933c198 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -390,11 +390,11 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( if app.UniqueUsernames { - free, err := m.userService.IsUsernameFree(form.Username, app.ID) + free, err := m.userService.IsUsernameFree(form.Username, app.ID) if err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to check username availability")} } - if !free { + if !free { return "", &models.GeneralError{Code: "username_taken", Message: models.ErrorUsernameTaken, Err: errors.New(models.ErrorUsernameTaken)} } } @@ -436,7 +436,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( user := &models.User{ ID: bson.NewObjectId(), AppID: app.ID, - Username: form.Username, + Username: form.Username, UniqUsername: app.UniqueUsernames, Email: form.Email, EmailVerified: false, diff --git a/pkg/persist/redis/watcher_test.go b/pkg/persist/redis/watcher_test.go index b1e67b8..28eaa3b 100644 --- a/pkg/persist/redis/watcher_test.go +++ b/pkg/persist/redis/watcher_test.go @@ -1,11 +1,14 @@ +// +build integration + package rediswatcher import ( - "github.com/go-redis/redis" - "github.com/stretchr/testify/assert" "sync" "testing" "time" + + "github.com/go-redis/redis" + "github.com/stretchr/testify/assert" ) func TestSubscribe(t *testing.T) { diff --git a/pkg/service/mfa.go b/pkg/service/mfa.go index 3c0b216..ce8569b 100644 --- a/pkg/service/mfa.go +++ b/pkg/service/mfa.go @@ -116,4 +116,4 @@ func (s *MfaService) RemoveUserProvider(provider *models.MfaUserProvider) error } return nil -} \ No newline at end of file +} diff --git a/pkg/service/one_time_token_test.go b/pkg/service/one_time_token_test.go index 6e3ae22..142762f 100644 --- a/pkg/service/one_time_token_test.go +++ b/pkg/service/one_time_token_test.go @@ -1,10 +1,13 @@ +// +build integration + package service import ( + "testing" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/go-redis/redis" "github.com/stretchr/testify/assert" - "testing" ) func TestOneTimeTokenSuccessCreate(t *testing.T) { From f70182dc571d058982661f230cba3cd7eb985953 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 5 Feb 2020 16:18:35 +0300 Subject: [PATCH 021/251] update Docker for local run --- Dockerfile | 4 ++-- docker-compose.yaml | 11 +---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9f37805..55e2f7d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.12.5-alpine AS builder +FROM golang:1.13-alpine AS builder RUN apk add bash ca-certificates git @@ -16,6 +16,6 @@ RUN CGO_ENABLED=0 GOOS=linux go build -a -o ./bin/auth1_auth . FROM alpine:3.9 RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* WORKDIR /application -COPY --from=builder /application /application +COPY --from=builder /application . ENTRYPOINT /application/bin/auth1_auth migration && /application/bin/auth1_auth server \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 5ab0a15..10a4e6c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -97,7 +97,7 @@ services: - auth1-redis:/data/redis auth1: - image: golang:1.11.5-stretch + build: . container_name: auth1 restart: unless-stopped depends_on: @@ -106,11 +106,6 @@ services: - hydra networks: - subnet - volumes: - - .:/go/src/auth-one - - $GOPATH/pkg/mod:/go/pkg/mod - working_dir: /go/src/auth-one - command: bash -c "go run main.go migration && go run main.go server" environment: - GO111MODULE=on - AUTHONE_SERVER_PORT=8080 @@ -125,12 +120,8 @@ services: volumes: auth1-mongo: - external: true auth1-redis: - external: true auth1-postgres: - external: true networks: subnet: - external: true From 24f1767237b4da5c1243487f4ac4c4a135f95768 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 5 Feb 2020 16:31:29 +0300 Subject: [PATCH 022/251] cache mods on travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b5de187..2db416c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ sudo: false go: - 1.12.x +cache: + directories: + - $GOPATH/pkg/mod + stages: - test - name: deploy @@ -18,7 +22,6 @@ jobs: env: - AUTHONE_DATABASE_USER=travis - AUTHONE_DATABASE_PASSWORD=test - - GO111MODULE=on before_script: - mongo auth-one --eval 'db.createUser({user:"travis",pwd:"test",roles:["readWrite"]});' script: From 7058e63fed5191e5f4849a949359d0459e2020db Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 5 Feb 2020 16:37:58 +0300 Subject: [PATCH 023/251] update CI go --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2db416c..cc0034a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go sudo: false go: - - 1.12.x + - 1.13.x cache: directories: From 0d372f55b7f055fe22a76463c70f83f9b2650505 Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 5 Feb 2020 17:15:50 +0300 Subject: [PATCH 024/251] update helm chart --- .helm/templates/ingress.yaml | 18 +++++++++++------- .helm/values.yaml | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 93d34b8..82dac05 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -1,4 +1,8 @@ {{- $endpoint := .Values.backend -}} +{{- $hydraSvc := "hydra-external"}} +{{- if eq .Release.Name "qilin-p1auth1" }} +{{- $hydraSvc := "hydra-external-qilin"}} +{{-end }} apiVersion: extensions/v1beta1 kind: Ingress metadata: @@ -31,25 +35,25 @@ spec: servicePort: {{ $endpoint.service.port }} - path: /userinfo backend: - serviceName: hydra + serviceName: $hydraSvc servicePort: 4444 - path: /oauth2/auth backend: - serviceName: hydra + serviceName: $hydraSvc servicePort: 4444 - path: /oauth2/token backend: - serviceName: hydra + serviceName: $hydraSvc servicePort: 4444 - path: /oauth2/revoke backend: - serviceName: hydra + serviceName: $hydraSvc servicePort: 4444 - path: /oauth2/userinfo backend: - serviceName: hydra + serviceName: $hydraSvc servicePort: 4444 - path: /.well-known/jwks.json backend: - serviceName: hydra - servicePort: 4444 + serviceName: $hydraSvc + servicePort: 4444 diff --git a/.helm/values.yaml b/.helm/values.yaml index dd77c19..af7ae8f 100644 --- a/.helm/values.yaml +++ b/.helm/values.yaml @@ -2,8 +2,8 @@ # Declare variables to be passed into your templates. enableRedis: true -enableMongo: true -enableHydra: true +enableMongo: false +enableHydra: false enableCertIssuer: true enableHydraDebug: false From 58edba5f9f99b5394cc7021e2e84235f90ed9632 Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 5 Feb 2020 17:31:29 +0300 Subject: [PATCH 025/251] fix helm chart --- .helm/templates/ingress.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 82dac05..2181c24 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -2,7 +2,7 @@ {{- $hydraSvc := "hydra-external"}} {{- if eq .Release.Name "qilin-p1auth1" }} {{- $hydraSvc := "hydra-external-qilin"}} -{{-end }} +{{- end }} apiVersion: extensions/v1beta1 kind: Ingress metadata: From 8cad6ddb380bf5a02297586d39e04fa64ee6371b Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 5 Feb 2020 17:33:23 +0300 Subject: [PATCH 026/251] fix helm chart --- .helm/templates/ingress.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 2181c24..74ff3a6 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -35,25 +35,25 @@ spec: servicePort: {{ $endpoint.service.port }} - path: /userinfo backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 - path: /oauth2/auth backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 - path: /oauth2/token backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 - path: /oauth2/revoke backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 - path: /oauth2/userinfo backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 - path: /.well-known/jwks.json backend: - serviceName: $hydraSvc + serviceName: {{ $hydraSvc }} servicePort: 4444 From 198548d9daf63a5f3c5395bf93a32b89c29dd99c Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 5 Feb 2020 18:36:58 +0300 Subject: [PATCH 027/251] slack notifications from travis --- .travis.yml | 79 ++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2cec13f..3d08f32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,43 +1,36 @@ -language: go -sudo: false -go: - - 1.12.x - -stages: - - test - - name: deploy - if: branch IN (master, develop) - -jobs: - include: - - stage: test - services: - - mongodb - - redis-server - install: true - env: - - AUTHONE_DATABASE_USER=travis - - AUTHONE_DATABASE_PASSWORD=test - - GO111MODULE=on - before_script: - - mongo auth-one --eval 'db.createUser({user:"travis",pwd:"test",roles:["readWrite"]});' - script: - - go test ./... -coverprofile=coverage.out -covermode=atomic -p=1 - after_success: - - bash <(curl -s https://codecov.io/bash) - - stage: deploy - services: docker - install: true - script: - #- 'curl -H "Content-Type: application/json;" -X POST -d "{\"PROJECT\": \"$TRAVIS_REPO_SLUG\", \"BRANCH\": \"$TRAVIS_BRANCH\"}" $JENKINS' - - docker run -it - -e JENKINS_AUTH_TOKEN=$JENKINS_AUTH_TOKEN - -e JENKINS_BUILD_TOKEN=$JENKINS_BUILD_TOKEN - -e JENKINS_BUILD_PROJECT=$TRAVIS_REPO_SLUG - -e JENKINS_BUILD_BRANCH=$TRAVIS_BRANCH - p1hub/p1jenkinstrigger - -notifications: - email: false - slack: - secure: OJFdeQ3znWtkHgoTT20tuzTvNq25VmQx0AurlIL779YGZ1jopNquEnH8x0u1SDWgUk+vpFxwRoMHRqsrXO6tv3E09XAh+mvjEoSKoJSfV46EAg0gClFtGaDPMAv8M/lZfLllcXXi5NDxEnO1tQoWOKU/CgZNf6Q/fd1iq/SHnMujANXj97r/u20Ikiax0ZE25kVk6V8Xbqeni/1wj70yJWxJPqALVJ/F17soB4xx8wKXIydZ367a8EzHMzkFLcffit1d/5GS5BKdYq0s0XoQZh91T4r/vhdJzxOEW70ANVkDGc8ELF/XsVzadq+7s0UHS5seNwj6nku7B44LcFSnNWvF+lapwYTG+PDrfIt7XImL7V/n+nWxGuuZZOOWpwb122qzLQfj2tzAjufVa/RKAU0oOxpWEBYK0W3SiRphnN4UN3wm5n/4Iav2Kt8j2MEhovXEGUJMdTXeozATEipJrnBWWA0jYhnmEG2H/DEqe73Wg+zpvaJBA5dN7lI5Vr49n/vtCgES1yYbNgefCQTPgEazOQp9V3ovLMBt7Qw3d8d4Y2IJuoYF95gw/i8ZnD4kQ15OPAruDYneU6j2ilKZOkvsf9NjaEopVrdbAXnxTsvqUEkUDtR4lNxhKRyP/cpmU1SCMd4Pa5mValhOV+N3rQQ+fysjUkfMZbYTZ+m4zBw= +language: go +sudo: false +go: +- 1.12.x +stages: +- test +- name: deploy + if: branch IN (master, develop) +jobs: + include: + - stage: test + services: + - mongodb + - redis-server + install: true + env: + - AUTHONE_DATABASE_USER=travis + - AUTHONE_DATABASE_PASSWORD=test + - GO111MODULE=on + before_script: + - mongo auth-one --eval 'db.createUser({user:"travis",pwd:"test",roles:["readWrite"]});' + script: + - go test ./... -coverprofile=coverage.out -covermode=atomic -p=1 + after_success: + - bash <(curl -s https://codecov.io/bash) + - stage: deploy + services: docker + install: true + script: + - docker run -it -e JENKINS_AUTH_TOKEN=$JENKINS_AUTH_TOKEN -e JENKINS_BUILD_TOKEN=$JENKINS_BUILD_TOKEN + -e JENKINS_BUILD_PROJECT=$TRAVIS_REPO_SLUG -e JENKINS_BUILD_BRANCH=$TRAVIS_BRANCH + p1hub/p1jenkinstrigger +notifications: + email: false + slack: + secure: UViqMku6a56CQYktC7q5ewDbH6Q0IlnaDEgaPGIm8JNmuYAmskfT8o41erOFy5V5IMvvd+L7xYg9A/5wd/pxQ3Yela6KdzymXN49bR+ZfyESspL30nkff6hs1DRBdXaGKS0y47i7C5c1VwYJZAlj1l+e/NPOyXgXSSVZsrqlL2FQmuP5vza0ACTkXxAuJ+qn59P/r0825qTbC6ZM9v/z/vpG8zjLc3jyUMkm7VZ74aV6c4jqyi8C/fbRs2OeBwDsnjf/GM222tMYyAjzyu+l/9O4I4RDljcTsDl5QgH6FpTK4/09d7cyTcyceCCmze/9dlOww/ARCb6Tyrj2bcXd89n58sUM1CJooIIL1HzvhA9xHmSwNifkWifql95HnqEJbNfYe1MhJB3llt/cNIzQreiNCmWdNSBcFaYqpnHF8GXYbhEbNCwnBhTsOihSUWe5crEhBgOYqqqUrnOcLXVytvgQSluW+d/krH/ngPEIiScSG3pmzV+JX6Z85bb8XXXJZ8zTa14y6VD7w8zFg3jLhuCDCzov2rT0kJN+fwxCBn8OD57tVLqGoVdNSbvcfa2mLdeHGTiS/MDK4SAuIwfI0SvHML3e1lm6tgXLZeuI4Qk3nFRbKWEV3gwGlUax55PHuxEG8urnb/QgZD8K26/kc0tjzmmtWCeJY3LtaYmYa4I= From aab6f60edca496fc6834faadd9441a8db3ce98a1 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Thu, 6 Feb 2020 08:06:41 +0300 Subject: [PATCH 028/251] recaptcha verification --- pkg/api/captcha.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++ pkg/api/mfa.go | 3 +- pkg/api/server.go | 22 ++++++------ 3 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 pkg/api/captcha.go diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go new file mode 100644 index 0000000..f03f8ec --- /dev/null +++ b/pkg/api/captcha.go @@ -0,0 +1,90 @@ +package api + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" + "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/labstack/echo/v4" +) + +func InitCaptcha(cfg *Server) error { + g := cfg.Echo.Group("/captcha", func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + db := c.Get("database").(database.MgoSession) + c.Set("mfa_manager", manager.NewMFAManager(db, cfg.Registry)) + + return next(c) + } + }) + + g.POST("/re3", captchaVerify) + + return nil +} + +func captchaVerify(ctx echo.Context) error { + var r struct { + Token string `json:"token"` + } + // m := ctx.Get("mfa_manager").(*manager.MFAManager) + + if err := ctx.Bind(&r); err != nil { + e := &models.GeneralError{ + Code: BadRequiredCodeCommon, + Message: models.ErrorInvalidRequestParameters, + } + ctx.Error(err) + return ctx.JSON(http.StatusBadRequest, e) + } + + result, err := verifyRecaptcha3(r.Token) + if err != nil { + ctx.Error(err) + return ctx.JSON(http.StatusInternalServerError, &models.GeneralError{ + Code: BadRequiredCodeCommon, + Message: models.ErrorInvalidRequestParameters, + }) + } + + return ctx.JSON(http.StatusOK, map[string]interface{}{ + "success": result, + }) +} + +func verifyRecaptcha3(token string) (bool, error) { + resp, err := http.PostForm("https://www.google.com/recaptcha/api/siteverify", url.Values{ + "secret": {"6Lea_dUUAAAAAK294XwQmOIujxW8ssNRk_zWU5AB"}, + "response": {token}, + // "remoteip" + }) + if err != nil { + return false, err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return false, err + } + + var res struct { + Success bool `json:"success"` //: true, + ChallengeTs string `json:"challenge_ts"` //: "2020-02-05T15:26:33Z", + Hostname string `json:"hostname"` //: "localhost", + Score float64 `json:"score"` //: 0.9, + Action string `json:"action"` //: "homepage" + ErrorCodes []string `json:"error_codes"` + } + + if err := json.Unmarshal(data, &res); err != nil { + return false, err + } + + if res.Success && res.Score > 0.5 { + return true, nil + } + return false, nil +} diff --git a/pkg/api/mfa.go b/pkg/api/mfa.go index c39c550..9036a7c 100644 --- a/pkg/api/mfa.go +++ b/pkg/api/mfa.go @@ -2,12 +2,13 @@ package api import ( "fmt" + "net/http" + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/labstack/echo/v4" - "net/http" ) func InitMFA(cfg *Server) error { diff --git a/pkg/api/server.go b/pkg/api/server.go index 8f9411c..2162039 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -2,6 +2,17 @@ package api import ( "context" + "html/template" + "io" + "net/http" + "os" + "os/signal" + "reflect" + "strconv" + "strings" + "syscall" + "time" + "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" @@ -16,16 +27,6 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" - "html/template" - "io" - "net/http" - "os" - "os/signal" - "reflect" - "strconv" - "strings" - "syscall" - "time" ) // ServerConfig contains common configuration parameters for start application server @@ -200,6 +201,7 @@ func (s *Server) setupRoutes() error { InitManage, InitOauth2, InitHealth, + InitCaptcha, } for _, r := range routes { From 78a7185640df0a2f78e5efe102963eb89e633079 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Thu, 6 Feb 2020 13:41:20 +0300 Subject: [PATCH 029/251] fix naming --- pkg/manager/oauth2.go | 4 ++-- pkg/models/user.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 2ecba61..a0b32e0 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -361,7 +361,7 @@ func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, return false, &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} } - if app.UniqueUsernames == false { + if !app.UniqueUsernames { return true, nil } @@ -437,7 +437,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( ID: bson.NewObjectId(), AppID: app.ID, Username: form.Username, - UniqUsername: app.UniqueUsernames, + UniqueUsername: app.UniqueUsernames, Email: form.Email, EmailVerified: false, Blocked: false, diff --git a/pkg/models/user.go b/pkg/models/user.go index 9da0f68..ae913bd 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -30,8 +30,8 @@ type User struct { // Username is the nickname of the user. Username string `bson:"username" json:"username"` - // UniqUsername is index flag that username must be unique within app. - UniqUsername bool `bson:"uniq_username" json:"-"` + // UniqueUsername is index flag that username must be unique within app. + UniqueUsername bool `bson:"unique_username" json:"-"` // Name is the name of the user. Contains first anf last name. Name string `bson:"name" json:"name"` From 5e6756c3ca2325ee1675c371300dfc01e601311c Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Thu, 6 Feb 2020 13:50:44 +0300 Subject: [PATCH 030/251] update field name in index --- .../migrations/20200204_01_create_username_unique_index.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/database/migrations/20200204_01_create_username_unique_index.go b/pkg/database/migrations/20200204_01_create_username_unique_index.go index d89613f..893b0b3 100644 --- a/pkg/database/migrations/20200204_01_create_username_unique_index.go +++ b/pkg/database/migrations/20200204_01_create_username_unique_index.go @@ -16,7 +16,7 @@ func init() { db.C(database.TableUser).EnsureIndex(mgo.Index{ Name: "Idx-Username-AppId", Key: []string{"username", "app_id"}, - PartialFilter: bson.M{"uniq_username": true}, + PartialFilter: bson.M{"unique_username": true}, Unique: true, Background: true, Sparse: false, From 15d27868febe80140ccbc67fd41b4de78e6e44a5 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Thu, 6 Feb 2020 20:37:25 +0300 Subject: [PATCH 031/251] captcha log, config, session --- cmd/main.go | 9 ++++- cmd/server.go | 1 + docker-compose.yaml | 8 +++- go.mod | 7 ++-- go.sum | 27 +++++++++++++ pkg/api/captcha.go | 84 +++++++++++++++----------------------- pkg/api/server.go | 7 ++++ pkg/config/config.go | 9 +++++ pkg/service/recaptcha.go | 87 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 181 insertions(+), 58 deletions(-) create mode 100644 pkg/service/recaptcha.go diff --git a/cmd/main.go b/cmd/main.go index 6c8c71d..a90bb0c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,10 +1,11 @@ package cmd import ( + "os" + "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/spf13/cobra" "go.uber.org/zap" - "os" ) var ( @@ -16,7 +17,11 @@ var ( func Execute() { var err error - logger, _ = zap.NewProduction() + if _, ok := os.LookupEnv("AUTHONE_LOGGING_DEV"); ok { + logger, _ = zap.NewDevelopment() + } else { + logger, _ = zap.NewProduction() + } zap.ReplaceGlobals(logger) defer logger.Sync() // flushes buffer, if any diff --git a/cmd/server.go b/cmd/server.go index c8cc249..f6584fe 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -89,6 +89,7 @@ func runServer(cmd *cobra.Command, args []string) { RedisClient: redisClient, HydraAdminApi: hydraSDK.Admin, Mailer: &cfg.Mailer, + Recaptcha: &cfg.Recaptcha, } server, err := api.NewServer(&serverConfig) diff --git a/docker-compose.yaml b/docker-compose.yaml index 10a4e6c..4726548 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -19,9 +19,10 @@ services: - AUTHONE_SERVER=http://auth1:8080 - AUTHONE_DEBUG=http://auth1:6060 - HYDRA_SERVER=http://hydra:4444 + - DOLLAR=$$ volumes: - ./etc/nginx/default.template:/etc/nginx/conf.d/default.template - command: bin/bash -c "envsubst < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" + command: bin/bash -c " envsubst < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" hydra-migrate: image: oryd/hydra:v1.0.0-rc.9_oryOS.10 @@ -107,7 +108,7 @@ services: networks: - subnet environment: - - GO111MODULE=on + - AUTHONE_LOGGING_DEV=true - AUTHONE_SERVER_PORT=8080 - AUTHONE_DATABASE_HOST=auth1-mongo - AUTHONE_DATABASE_NAME=auth-one @@ -117,6 +118,9 @@ services: - AUTHONE_SESSION_NETWORK=tcp - AUTHONE_SESSION_ADDRESS=auth1-redis:6379 - AUTHONE_MIGRATION_DIRECT=up + - AUTHONE_RECAPTCHA_KEY=6Lea_dUUAAAAAGV4L8JS7NSgmjOZjafXkS4flPEK + - AUTHONE_RECAPTCHA_SECRET=6Lea_dUUAAAAAK294XwQmOIujxW8ssNRk_zWU5AB + - AUTHONE_RECAPTCHA_HOSTNAME=localhost volumes: auth1-mongo: diff --git a/go.mod b/go.mod index 44c564a..4ea53a4 100644 --- a/go.mod +++ b/go.mod @@ -22,11 +22,12 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 github.com/juju/mgosession v1.0.0 // indirect + github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac github.com/kelseyhightower/envconfig v1.3.0 github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 - github.com/labstack/echo/v4 v4.0.0 - github.com/labstack/gommon v0.2.8 + github.com/labstack/echo/v4 v4.1.14 + github.com/labstack/gommon v0.3.0 github.com/micro/go-micro v1.8.0 github.com/micro/go-plugins v1.2.0 github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 @@ -38,7 +39,7 @@ require ( github.com/xakep666/mongo-migrate v0.1.0 github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect go.uber.org/zap v1.10.0 - golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 gopkg.in/go-playground/validator.v9 v9.29.1 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df diff --git a/go.sum b/go.sum index 535c1e4..24efb90 100644 --- a/go.sum +++ b/go.sum @@ -230,6 +230,7 @@ github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20181003173013-ead4ad1d2727/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI= @@ -526,6 +527,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 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.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -704,12 +706,15 @@ github.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20160818025724-3b7ece48644d/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/loggo v0.0.0-20190212223446-d976af380377/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/mgosession v1.0.0/go.mod h1:4zVjdmPhtQ+tFwByzM8UcGYKEqqiG9TvPArt210VNw4= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= github.com/juju/version v0.0.0-20160603194958-4ae6172c0062/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U= +github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac h1:mIYfqlPcFmuFpKMMMmq+pu7okWEWShiyW2w6/+2qDaY= +github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac/go.mod h1:yGXwCw1C3O7X2kkzB5gky65S4I5a0h4Ylic4xVo5D78= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= @@ -740,8 +745,12 @@ github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 h1:/vPhum06N github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442/go.mod h1:ELz8yG650dzTZBn+wLNi0ETVGWuxTdlpos8CV9EEJFY= github.com/labstack/echo/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= +github.com/labstack/echo/v4 v4.1.14 h1:h8XP66UfB3tUm+L3QPw7tmwAu3pJaA/nyfHPCcz46ic= +github.com/labstack/echo/v4 v4.1.14/go.mod h1:Q5KZ1vD3V5FEzjM79hjwVrC3ABr7F5IdM23bXQMRDGg= github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= +github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lestrrat-go/jwx v0.0.0-20180928232350-0d477e6a1f0e h1:BsBWIgqA7BFb5sdQeFVQqXYL0P9ZwiNYvL3nywtEmnY= @@ -791,6 +800,8 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -798,6 +809,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -1092,6 +1106,9 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4= +github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -1127,6 +1144,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= @@ -1167,6 +1185,8 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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= @@ -1230,6 +1250,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL 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 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= 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 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1304,6 +1326,10 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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= @@ -1425,6 +1451,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index f03f8ec..4d5d1b5 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -1,37 +1,50 @@ package api import ( - "encoding/json" - "io/ioutil" + "context" "net/http" - "net/url" - "github.com/ProtocolONE/auth1.protocol.one/pkg/database" - "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/labstack/echo/v4" ) func InitCaptcha(cfg *Server) error { - g := cfg.Echo.Group("/captcha", func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - db := c.Get("database").(database.MgoSession) - c.Set("mfa_manager", manager.NewMFAManager(db, cfg.Registry)) + c := &Captcha{ + recaptcha: cfg.Recaptcha, + session: service.NewSessionService(cfg.SessionConfig.Name), + } + cfg.Echo.Group("/captcha"). + POST("/re3", c.verify) - return next(c) - } - }) + return nil +} - g.POST("/re3", captchaVerify) +var captchaKey = "captcha" - return nil +type Captcha struct { + recaptcha *service.Recaptcha + session service.SessionService +} + +func CaptchaCompleted(ctx echo.Context, s service.SessionService) (bool, error) { + v, err := s.Get(ctx, captchaKey) + if err != nil { + return false, err + } + if v != nil { + if done, ok := v.(bool); ok { + return done, nil + } + } + return false, nil } -func captchaVerify(ctx echo.Context) error { +func (ctl *Captcha) verify(ctx echo.Context) error { var r struct { - Token string `json:"token"` + Token string `json:"token"` + Action string `json:"action"` } - // m := ctx.Get("mfa_manager").(*manager.MFAManager) if err := ctx.Bind(&r); err != nil { e := &models.GeneralError{ @@ -42,7 +55,7 @@ func captchaVerify(ctx echo.Context) error { return ctx.JSON(http.StatusBadRequest, e) } - result, err := verifyRecaptcha3(r.Token) + result, err := ctl.recaptcha.Verify(context.TODO(), r.Token, r.Action, "") // TODO ip if err != nil { ctx.Error(err) return ctx.JSON(http.StatusInternalServerError, &models.GeneralError{ @@ -51,40 +64,9 @@ func captchaVerify(ctx echo.Context) error { }) } + ctl.session.Set(ctx, captchaKey, result) + return ctx.JSON(http.StatusOK, map[string]interface{}{ "success": result, }) } - -func verifyRecaptcha3(token string) (bool, error) { - resp, err := http.PostForm("https://www.google.com/recaptcha/api/siteverify", url.Values{ - "secret": {"6Lea_dUUAAAAAK294XwQmOIujxW8ssNRk_zWU5AB"}, - "response": {token}, - // "remoteip" - }) - if err != nil { - return false, err - } - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return false, err - } - - var res struct { - Success bool `json:"success"` //: true, - ChallengeTs string `json:"challenge_ts"` //: "2020-02-05T15:26:33Z", - Hostname string `json:"hostname"` //: "localhost", - Score float64 `json:"score"` //: 0.9, - Action string `json:"action"` //: "homepage" - ErrorCodes []string `json:"error_codes"` - } - - if err := json.Unmarshal(data, &res); err != nil { - return false, err - } - - if res.Success && res.Score > 0.5 { - return true, nil - } - return false, nil -} diff --git a/pkg/api/server.go b/pkg/api/server.go index 2162039..cb2a12a 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -57,6 +57,9 @@ type ServerConfig struct { // Mailer contains settings for the postman service Mailer *config.Mailer + + // Recaptcha contains settings for recaptcha integration + Recaptcha *config.Recaptcha } // Server is the instance of the application @@ -78,6 +81,9 @@ type Server struct { // Registry is the registry service Registry service.InternalRegistry + + // Recaptcha is recaptcha integration + Recaptcha *service.Recaptcha } // Template is used to display HTML pages. @@ -101,6 +107,7 @@ func NewServer(c *ServerConfig) (*Server, error) { SessionConfig: c.SessionConfig, HydraConfig: c.HydraConfig, Registry: service.NewRegistryBase(registryConfig), + Recaptcha: service.NewRecaptcha(c.Recaptcha.Key, c.Recaptcha.Secret, c.Recaptcha.Hostname), } t := &Template{ diff --git a/pkg/config/config.go b/pkg/config/config.go index 45a71fa..c4c4ec9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -24,6 +24,9 @@ type Config struct { // Mailer contains settings for the postman service. Mailer Mailer + // Recaptcha contains settings for recaptcha integration. + Recaptcha Recaptcha + // MigrationDirect specifies direction for database migrations. MigrationDirect string `envconfig:"MIGRATION_DIRECT" required:"false"` } @@ -80,6 +83,12 @@ type Mailer struct { InsecureSkipVerify bool `envconfig:"SKIP_VERIFY" required:"false" default:"true"` } +type Recaptcha struct { + Key string `envconfig:"KEY" required:"false" default:""` + Secret string `envconfig:"SECRET" required:"false" default:""` + Hostname string `envconfig:"HOSTNAME" required:"false" default:""` +} + func Load() (*Config, error) { config := &Config{} return config, envconfig.Process("AUTHONE", config) diff --git a/pkg/service/recaptcha.go b/pkg/service/recaptcha.go new file mode 100644 index 0000000..8b67fad --- /dev/null +++ b/pkg/service/recaptcha.go @@ -0,0 +1,87 @@ +package service + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + + "github.com/juju/zaputil/zapctx" + "github.com/pkg/errors" + "go.uber.org/zap" +) + +// Recaptcha provides integration with google recaptcha v3 +type Recaptcha struct { + key string + secret string + hostname string +} + +// NewRecaptcha returns recaptcha integration service with provided key and secret +func NewRecaptcha(key, secret, hostname string) *Recaptcha { + return &Recaptcha{key, secret, hostname} +} + +// Key returns client key +func (r *Recaptcha) Key() string { + return r.key +} + +// Verify checks provided token in recaptcha service +func (r *Recaptcha) Verify(ctx context.Context, token, action, ip string) (bool, error) { + log := zapctx.Logger(ctx) + form := url.Values{ + "secret": {r.secret}, + "response": {token}, + } + if ip != "" { + form["remoteip"] = []string{ip} + } + + // TODO retry + resp, err := http.PostForm("https://www.google.com/recaptcha/api/siteverify", form) + if err != nil { + return false, errors.WithMessage(err, "recaptcha verify request failed") + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return false, errors.WithMessage(err, "recaptcha verify request failed") + } + + log.Debug("recaptcha verify", zap.ByteString("response", data)) + + var res struct { + Success bool `json:"success"` //: true, + ChallengeTs string `json:"challenge_ts"` //: "2020-02-05T15:26:33Z", + Hostname string `json:"hostname"` //: "localhost", + Score float64 `json:"score"` //: 0.9, + Action string `json:"action"` //: "homepage" + ErrorCodes []string `json:"error-codes"` + } + + if err := json.Unmarshal(data, &res); err != nil { + return false, errors.WithMessage(err, "recaptcha invalid response") + } + + if !res.Success { + log.Warn("recaptcha verify errors", zap.Strings("errors", res.ErrorCodes)) + return false, nil + } + + if action != "" && res.Action != action { + log.Warn("recaptcha actions doesn't match", zap.String("re_action", res.Action), zap.String("our_action", action)) + return false, nil + } + + if r.hostname != "" && res.Hostname != r.hostname { + log.Warn("recaptcha hostname doesn't match", zap.String("re_hostname", res.Hostname), zap.String("our_hostname", r.hostname)) + return false, nil + } + + if res.Score > 0.5 { + return true, nil + } + return false, nil +} From 03d6e0f4994fc4c45db0c003a6d5ce3436ebd039 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 10 Feb 2020 10:01:27 +0300 Subject: [PATCH 032/251] errors init --- pkg/api/apierror/error.go | 77 +++++++++++++++++++++++++++++++++++++++ pkg/api/oauth2.go | 33 +++++++++-------- pkg/api/server.go | 42 +++++++++++---------- pkg/helper/error.go | 5 ++- 4 files changed, 121 insertions(+), 36 deletions(-) create mode 100644 pkg/api/apierror/error.go diff --git a/pkg/api/apierror/error.go b/pkg/api/apierror/error.go new file mode 100644 index 0000000..f4d569f --- /dev/null +++ b/pkg/api/apierror/error.go @@ -0,0 +1,77 @@ +package apierror + +import ( + "fmt" + "net/http" + + "github.com/labstack/echo/v4" +) + +type Error struct { + Code int + Message string + Status uint16 +} + +func (e Error) Error() string { + return e.Message +} + +const ErrorPrefix = "errors.one.protocol.auth1." + +var ( + unknown = Error{1000, "unknown", http.StatusInternalServerError} + invalidRequest = Error{1001, "invalid_request", http.StatusBadRequest} + invalidParameters = Error{1002, "invalid_parameters", http.StatusBadRequest} +) + +func Unknown(err error) error { + return invalidRequest +} + +func InvalidRequest(err error) error { + return invalidRequest +} + +func InvalidParameters(err error) error { + return invalidParameters +} + +type Params *interface{} + +type Response struct { + Error string `json:"error"` + Code string `json:"code"` + RequestID string `json:"request_id"` + Params +} + +func Handler(err error, ctx echo.Context) { + rid := ctx.Response().Header().Get(echo.HeaderXRequestID) + + var code = http.StatusInternalServerError + var resp Response + + switch e := err.(type) { + case Error: + resp.Error = ErrorPrefix + e.Message + resp.Code = fmt.Sprintf("AU-%d", e.Code) + resp.RequestID = rid + code = int(e.Status) + } + + var m interface{} = map[string]interface{}{"param": "some"} + resp.Params = &m + + // Send response + if !ctx.Response().Committed { + if ctx.Request().Method == http.MethodHead { // Issue #608 + err = ctx.NoContent(code) + } else { + err = ctx.JSON(code, resp) + } + if err != nil { + ctx.Logger().Error(err) + } + } +} diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 8b942b3..f1c5df8 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -1,9 +1,9 @@ package api import ( - "fmt" "net/http" + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" @@ -81,26 +81,29 @@ func oauthLoginSubmit(ctx echo.Context) error { m := ctx.Get("oauth_manager").(*manager.OauthManager) if err := ctx.Bind(form); err != nil { - e := &models.GeneralError{ - Code: BadRequiredCodeCommon, - Message: models.ErrorInvalidRequestParameters, - } - ctx.Error(err) - return helper.JsonError(ctx, e) + return apierror.InvalidRequest(err) + // e := &models.GeneralError{ + // Code: BadRequiredCodeCommon, + // Message: models.ErrorInvalidRequestParameters, + // } + // ctx.Error(err) + // return helper.JsonError(ctx, e) } if err := ctx.Validate(form); err != nil { - e := &models.GeneralError{ - Code: fmt.Sprintf(BadRequiredCodeField, helper.GetSingleError(err).Field()), - Message: models.ErrorRequiredField, - } - ctx.Error(err) - return helper.JsonError(ctx, e) + return apierror.InvalidParameters(err) + // e := &models.GeneralError{ + // Code: fmt.Sprintf(BadRequiredCodeField, helper.GetSingleError(err).Field()), + // Message: models.ErrorRequiredField, + // } + // ctx.Error(err) + // return helper.JsonError(ctx, e) } url, err := m.Auth(ctx, form) if err != nil { - ctx.Error(err.Err) - return helper.JsonError(ctx, err) + return err + // ctx.Error(err.Err) + // return helper.JsonError(ctx, err) } return ctx.JSON(http.StatusOK, map[string]interface{}{"url": url}) diff --git a/pkg/api/server.go b/pkg/api/server.go index cb2a12a..88f49b5 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -13,11 +13,12 @@ import ( "syscall" "time" + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" - "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" + "github.com/ProtocolONE/mfa-service/pkg/proto" "github.com/boj/redistore" "github.com/go-redis/redis" @@ -113,44 +114,47 @@ func NewServer(c *ServerConfig) (*Server, error) { t := &Template{ templates: template.Must(template.ParseGlob("public/templates/*.html")), } - server.Echo.Renderer = t - server.Echo.HTTPErrorHandler = helper.ErrorHandler - server.Echo.Use(ZapLogger(zap.L())) - server.Echo.Use(middleware.Recover()) + s := server.Echo + s.Renderer = t + s.HTTPErrorHandler = apierror.Handler //helper.ErrorHandler + s.Use(ZapLogger(zap.L())) + s.Use(middleware.Recover()) + s.Use(middleware.RequestID()) + s.Use(func(next echo.HandlerFunc) echo.HandlerFunc { + return func(ctx echo.Context) error { + var logger = zap.L().With( + zap.String("request_id", ctx.Response().Header().Get(echo.HeaderXRequestID)), + ) + ctx.Set("logger", logger) + + return next(ctx) + } + }) // TODO: Validate origins for each application by settings - server.Echo.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + s.Use(middleware.CORSWithConfig(middleware.CORSConfig{ AllowHeaders: []string{"authorization", "content-type"}, AllowOrigins: c.ApiConfig.AllowOrigins, AllowCredentials: c.ApiConfig.AllowCredentials, AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete, http.MethodOptions}, })) - server.Echo.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ + s.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "header:X-XSRF-TOKEN", CookieName: "_csrf", Skipper: csrfSkipper, })) - server.Echo.Use(session.Middleware(c.SessionStore)) - server.Echo.Use(middleware.RequestID()) - server.Echo.Use(func(next echo.HandlerFunc) echo.HandlerFunc { + s.Use(session.Middleware(c.SessionStore)) + s.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(ctx echo.Context) error { db := c.MgoSession.Copy() defer db.Close() ctx.Set("database", db) - logger := zap.L().With( - zap.String( - echo.HeaderXRequestID, - ctx.Response().Header().Get(echo.HeaderXRequestID), - ), - ) - ctx.Set("logger", logger) - return next(ctx) } }) - registerCustomValidator(server.Echo) + registerCustomValidator(s) if err := server.setupRoutes(); err != nil { zap.L().Fatal("Setup routes failed", zap.Error(err)) diff --git a/pkg/helper/error.go b/pkg/helper/error.go index 19798a8..721cfc9 100644 --- a/pkg/helper/error.go +++ b/pkg/helper/error.go @@ -2,13 +2,14 @@ package helper import ( "bytes" + "io/ioutil" + "net/http" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/labstack/echo/v4" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/go-playground/validator.v9" - "io/ioutil" - "net/http" ) // GetSingleError returns the first error from the list of validation errors. From 46075a0aff58111af86cc3e405172566332fb8ab Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 10 Feb 2020 10:18:36 +0300 Subject: [PATCH 033/251] requires captcha option --- Dockerfile | 3 ++- go.mod.cache | 56 +++++++++++++++++++++++++++++++++++++++ pkg/api/captcha.go | 13 --------- pkg/manager/manage.go | 2 ++ pkg/manager/oauth2.go | 23 ++++++++++++++++ pkg/models/application.go | 3 +++ pkg/models/manage.go | 1 + 7 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 go.mod.cache diff --git a/Dockerfile b/Dockerfile index 55e2f7d..a3b496f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,8 @@ RUN apk add bash ca-certificates git WORKDIR /application -ENV GO111MODULE=on +COPY go.mod.cache go.mod +RUN go mod download COPY go.mod go.sum ./ RUN go mod download diff --git a/go.mod.cache b/go.mod.cache new file mode 100644 index 0000000..4ea53a4 --- /dev/null +++ b/go.mod.cache @@ -0,0 +1,56 @@ +module github.com/ProtocolONE/auth1.protocol.one + +require ( + github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb + github.com/ProtocolONE/mfa-service v0.1.1 + github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect + github.com/alicebob/miniredis v2.5.0+incompatible + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 + github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/elliotchance/redismock v1.5.1 + github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 + github.com/go-openapi/runtime v0.19.0 + github.com/go-openapi/strfmt v0.19.0 + github.com/go-openapi/swag v0.19.0 + github.com/go-redis/redis v6.15.2+incompatible + github.com/golang/oauth2 v0.0.0-20181203162652-d668ce993890 + github.com/golang/protobuf v1.3.2 + github.com/google/uuid v1.1.1 + github.com/gorilla/securecookie v1.1.1 + github.com/gorilla/sessions v1.1.3 + github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect + github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 + github.com/juju/mgosession v1.0.0 // indirect + github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac + github.com/kelseyhightower/envconfig v1.3.0 + github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b + github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 + github.com/labstack/echo/v4 v4.1.14 + github.com/labstack/gommon v0.3.0 + github.com/micro/go-micro v1.8.0 + github.com/micro/go-plugins v1.2.0 + github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 + github.com/pkg/errors v0.8.1 + github.com/sirupsen/logrus v1.4.2 + github.com/spf13/cobra v0.0.3 + github.com/spf13/viper v1.3.2 + github.com/stretchr/testify v1.4.0 + github.com/xakep666/mongo-migrate v0.1.0 + github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect + go.uber.org/zap v1.10.0 + golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + gopkg.in/go-playground/validator.v9 v9.29.1 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce + gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 + gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect + gopkg.in/yaml.v2 v2.2.2 +) + +replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.1 + +replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.0 + +go 1.13 diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index 4d5d1b5..7ef2c65 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -27,19 +27,6 @@ type Captcha struct { session service.SessionService } -func CaptchaCompleted(ctx echo.Context, s service.SessionService) (bool, error) { - v, err := s.Get(ctx, captchaKey) - if err != nil { - return false, err - } - if v != nil { - if done, ok := v.(bool); ok { - return done, nil - } - } - return false, nil -} - func (ctl *Captcha) verify(ctx echo.Context) error { var r struct { Token string `json:"token"` diff --git a/pkg/manager/manage.go b/pkg/manager/manage.go index 780f090..75485b2 100644 --- a/pkg/manager/manage.go +++ b/pkg/manager/manage.go @@ -98,6 +98,7 @@ func (m *ManageManager) CreateApplication(ctx echo.Context, form *models.Applica AuthRedirectUrls: form.Application.AuthRedirectUrls, HasSharedUsers: form.Application.HasSharedUsers, UniqueUsernames: form.Application.UniqueUsernames, + RequiresCaptcha: form.Application.RequiresCaptcha, PasswordSettings: &models.PasswordSettings{ BcryptCost: models.PasswordBcryptCostDefault, Min: models.PasswordMinDefault, @@ -170,6 +171,7 @@ func (m *ManageManager) UpdateApplication(ctx echo.Context, id string, form *mod a.AuthRedirectUrls = form.Application.AuthRedirectUrls a.HasSharedUsers = form.Application.HasSharedUsers a.UniqueUsernames = form.Application.UniqueUsernames + a.RequiresCaptcha = form.Application.RequiresCaptcha if err := m.r.ApplicationService().Update(a); err != nil { return nil, &models.GeneralError{Message: "Unable to update application", Err: errors.Wrap(err, "Unable to update application")} diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 933c198..998c7ab 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -373,6 +373,19 @@ func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, return ok, nil } +func CaptchaCompleted(ctx echo.Context, s service.SessionService) (bool, error) { + v, err := s.Get(ctx, "captcha") + if err != nil { + return false, err + } + if v != nil { + if done, ok := v.(bool); ok { + return done, nil + } + } + return false, nil +} + func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) (string, *models.GeneralError) { if err := m.session.Set(ctx, loginRememberKey, form.Remember); err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error saving session")} @@ -388,6 +401,16 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} } + if app.RequiresCaptcha { + ok, err := CaptchaCompleted(ctx, m.session) + if err != nil { + return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error validate captcha")} + } + if !ok { + return "", &models.GeneralError{Code: "captcha", Message: models.ErrorCaptchaRequired} + } + } + if app.UniqueUsernames { free, err := m.userService.IsUsernameFree(form.Username, app.ID) diff --git a/pkg/models/application.go b/pkg/models/application.go index 00aad5c..1c97741 100644 --- a/pkg/models/application.go +++ b/pkg/models/application.go @@ -70,6 +70,9 @@ type Application struct { // UniqueUsernames determines whether app users must have unique usernames UniqueUsernames bool `bson:"unique_usernames" json:"unique_usernames"` + // RequiresCaptcha determines whether app users must have complete captcha verification + RequiresCaptcha bool `bson:"requires_captcha" json:"requires_captcha"` + // PasswordSettings contains settings for valid password criteria. PasswordSettings *PasswordSettings `bson:"password_settings" json:"password_settings"` diff --git a/pkg/models/manage.go b/pkg/models/manage.go index 3f1e2bd..f44b93f 100644 --- a/pkg/models/manage.go +++ b/pkg/models/manage.go @@ -24,6 +24,7 @@ type ApplicationFormApp struct { AuthRedirectUrls []string `bson:"auth_redirect_urls" json:"auth_redirect_urls" validate:"required"` HasSharedUsers bool `bson:"has_shared_users" json:"has_shared_users"` UniqueUsernames bool `bson:"unique_usernames" json:"unique_usernames"` + RequiresCaptcha bool `bson:"requires_captcha" json:"requires_captcha"` } func (a *ApplicationFormApp) MarshalLogObject(enc zapcore.ObjectEncoder) error { From 22df8cf34a6226c115688547a07817b00ac5141f Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Mon, 10 Feb 2020 11:45:15 +0300 Subject: [PATCH 034/251] fix helm template --- .helm/templates/ingress.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 74ff3a6..5c95ef3 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -1,8 +1,5 @@ {{- $endpoint := .Values.backend -}} -{{- $hydraSvc := "hydra-external"}} -{{- if eq .Release.Name "qilin-p1auth1" }} -{{- $hydraSvc := "hydra-external-qilin"}} -{{- end }} +{{- $hydraSvc := printf "hydra-external-%s" .Release.Name}} apiVersion: extensions/v1beta1 kind: Ingress metadata: From e74fba5478ac0d165995e47b9785818f1514513b Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 11 Feb 2020 08:50:22 +0300 Subject: [PATCH 035/251] new errors for login/signup/checkUsername/captcha --- pkg/api/apierror/error.go | 37 ++++++++++++--------- pkg/api/captcha.go | 16 +++------- pkg/api/oauth2.go | 38 ++++------------------ pkg/manager/oauth2.go | 67 ++++++++++++++++++++------------------- 4 files changed, 67 insertions(+), 91 deletions(-) diff --git a/pkg/api/apierror/error.go b/pkg/api/apierror/error.go index f4d569f..32203d8 100644 --- a/pkg/api/apierror/error.go +++ b/pkg/api/apierror/error.go @@ -23,6 +23,15 @@ var ( unknown = Error{1000, "unknown", http.StatusInternalServerError} invalidRequest = Error{1001, "invalid_request", http.StatusBadRequest} invalidParameters = Error{1002, "invalid_parameters", http.StatusBadRequest} + + InvalidChallenge = Error{1003, "invalid_challenge", http.StatusBadRequest} + InvalidToken = Error{1004, "invalid_token", http.StatusBadRequest} + InvalidClient = Error{1005, "invalid_client", http.StatusBadRequest} + InvalidEmail = Error{1006, "invalid_credentials", http.StatusBadRequest} + InvalidPassword = Error{1007, "invalid_credentials", http.StatusBadRequest} + UsernameTaken = Error{1008, "username_already_exists", http.StatusBadRequest} + WeakPassword = Error{1009, "password_does_not_meet_policy", http.StatusBadRequest} + EmailRegistered = Error{1010, "email_already_registered", http.StatusBadRequest} ) func Unknown(err error) error { @@ -37,35 +46,33 @@ func InvalidParameters(err error) error { return invalidParameters } -type Params *interface{} - type Response struct { Error string `json:"error"` Code string `json:"code"` RequestID string `json:"request_id"` - Params } func Handler(err error, ctx echo.Context) { rid := ctx.Response().Header().Get(echo.HeaderXRequestID) - var code = http.StatusInternalServerError - var resp Response - - switch e := err.(type) { - case Error: - resp.Error = ErrorPrefix + e.Message - resp.Code = fmt.Sprintf("AU-%d", e.Code) - resp.RequestID = rid - code = int(e.Status) + var e Error + if x, ok := err.(Error); ok { + e = x + } else { + ctx.Logger().Error(err) + e = unknown } - var m interface{} = map[string]interface{}{"param": "some"} - resp.Params = &m + var resp = Response{ + Error: ErrorPrefix + e.Message, + Code: fmt.Sprintf("AU-%d", e.Code), + RequestID: rid, + } + var code = int(e.Status) // Send response if !ctx.Response().Committed { - if ctx.Request().Method == http.MethodHead { // Issue #608 + if ctx.Request().Method == http.MethodHead { err = ctx.NoContent(code) } else { err = ctx.JSON(code, resp) diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index 4d5d1b5..a2c9c13 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -4,9 +4,10 @@ import ( "context" "net/http" - "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/labstack/echo/v4" + "github.com/pkg/errors" ) func InitCaptcha(cfg *Server) error { @@ -47,21 +48,12 @@ func (ctl *Captcha) verify(ctx echo.Context) error { } if err := ctx.Bind(&r); err != nil { - e := &models.GeneralError{ - Code: BadRequiredCodeCommon, - Message: models.ErrorInvalidRequestParameters, - } - ctx.Error(err) - return ctx.JSON(http.StatusBadRequest, e) + return apierror.InvalidRequest(err) } result, err := ctl.recaptcha.Verify(context.TODO(), r.Token, r.Action, "") // TODO ip if err != nil { - ctx.Error(err) - return ctx.JSON(http.StatusInternalServerError, &models.GeneralError{ - Code: BadRequiredCodeCommon, - Message: models.ErrorInvalidRequestParameters, - }) + return errors.Wrap(err, "unable to verify captcha") } ctl.session.Set(ctx, captchaKey, result) diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index f1c5df8..4d7a483 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -82,28 +82,14 @@ func oauthLoginSubmit(ctx echo.Context) error { if err := ctx.Bind(form); err != nil { return apierror.InvalidRequest(err) - // e := &models.GeneralError{ - // Code: BadRequiredCodeCommon, - // Message: models.ErrorInvalidRequestParameters, - // } - // ctx.Error(err) - // return helper.JsonError(ctx, e) } if err := ctx.Validate(form); err != nil { return apierror.InvalidParameters(err) - // e := &models.GeneralError{ - // Code: fmt.Sprintf(BadRequiredCodeField, helper.GetSingleError(err).Field()), - // Message: models.ErrorRequiredField, - // } - // ctx.Error(err) - // return helper.JsonError(ctx, e) } url, err := m.Auth(ctx, form) if err != nil { return err - // ctx.Error(err.Err) - // return helper.JsonError(ctx, err) } return ctx.JSON(http.StatusOK, map[string]interface{}{"url": url}) @@ -202,18 +188,12 @@ func oauthSignUp(ctx echo.Context) error { m := ctx.Get("oauth_manager").(*manager.OauthManager) if err := ctx.Bind(form); err != nil { - e := &models.GeneralError{ - Code: BadRequiredCodeCommon, - Message: models.ErrorInvalidRequestParameters, - } - ctx.Error(err) - return helper.JsonError(ctx, e) + return apierror.InvalidRequest(err) } url, err := m.SignUp(ctx, form) if err != nil { - ctx.Error(err.Err) - return ctx.JSON(http.StatusBadRequest, err) + return err } return ctx.JSON(http.StatusOK, map[string]interface{}{"url": url}) @@ -225,23 +205,19 @@ func oauthCheckUsername(ctx echo.Context) error { } if err := ctx.Bind(&r); err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) + return apierror.InvalidRequest(err) } m := ctx.Get("oauth_manager").(*manager.OauthManager) ok, err := m.IsUsernameFree(ctx, r.Username) if err != nil { - ctx.Error(err) - return ctx.JSON(http.StatusInternalServerError, err) - } - - if ok { - return ctx.JSON(http.StatusOK, map[string]interface{}{}) + return err } - return ctx.JSON(http.StatusForbidden, map[string]interface{}{}) + return ctx.JSON(http.StatusOK, map[string]interface{}{ + "available": ok, + }) } func oauthCallback(ctx echo.Context) error { diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 933c198..66029d5 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -2,6 +2,7 @@ package manager import ( "fmt" + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -48,7 +49,7 @@ type OauthManagerInterface interface { // one-time authorization token (obtained after authorization through social networks). // // After successful authorization, the URL for the redirect will be returned to pass the agreement consent process. - Auth(echo.Context, *models.Oauth2LoginSubmitForm) (string, *models.GeneralError) + Auth(echo.Context, *models.Oauth2LoginSubmitForm) (string, error) // Consent prompts the user to accept the consent. Consent(echo.Context, *models.Oauth2ConsentForm) ([]string, *models.GeneralError) @@ -71,7 +72,7 @@ type OauthManagerInterface interface { // SignUp registers a new user using login and password. // // After successful registration, the URL for the redirect will be returned to pass the agreement consent process. - SignUp(echo.Context, *models.Oauth2SignUpForm) (string, *models.GeneralError) + SignUp(echo.Context, *models.Oauth2SignUpForm) (string, error) // IsUsernameFree checks if username is available for signup IsUsernameFree(ctx echo.Context, username string) (bool, error) @@ -165,10 +166,10 @@ func (m *OauthManager) CheckAuth(ctx echo.Context, form *models.Oauth2LoginForm) return req.Payload.Client.ClientID, user, ipc, "", nil } -func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm) (string, *models.GeneralError) { +func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm) (string, error) { req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Context: ctx.Request().Context(), Challenge: form.Challenge}) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorLoginChallenge, Err: errors.Wrap(err, "Unable to get client from login request")} + return "", apierror.InvalidChallenge } userId := req.Payload.Subject @@ -176,42 +177,42 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm if req.Payload.Subject == "" || req.Payload.Subject != form.PreviousLogin { if form.Token != "" { if err := m.r.OneTimeTokenService().Use(form.Token, userIdentity); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} + return "", apierror.InvalidToken } } else { app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(req.Payload.Client.ClientID)) if err != nil { - return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} + return "", errors.Wrap(err, "unable to load application") } ipc := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) if ipc == nil { - return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.New("Unable to get identity provider")} + return "", errors.New("unable to get identity provider") } userIdentity, err = m.userIdentityService.Get(app, ipc, form.Email) if err != nil { - return "", &models.GeneralError{Code: "email", Message: models.ErrorLoginIncorrect, Err: errors.Wrap(err, "Unable to get user identity")} + return "", apierror.InvalidEmail } encryptor := models.NewBcryptEncryptor(&models.CryptConfig{Cost: app.PasswordSettings.BcryptCost}) if err := encryptor.Compare(userIdentity.Credential, form.Password); err != nil { - return "", &models.GeneralError{Code: "password", Message: models.ErrorPasswordIncorrect, Err: errors.Wrap(err, "Bad user password")} + return "", apierror.InvalidPassword } } user, err := m.userService.Get(userIdentity.UserID) if err != nil { - return "", &models.GeneralError{Code: "email", Message: models.ErrorLoginIncorrect, Err: errors.Wrap(err, "Unable to get user")} + return "", errors.Wrap(err, "unable to get user") } user.LoginsCount = user.LoginsCount + 1 if err := m.userService.Update(user); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUpdateUser, Err: errors.Wrap(err, "Unable to update user")} + return "", errors.Wrap(err, "unable to update user") } if err := m.authLogService.Add(ctx.RealIP(), ctx.Request().UserAgent(), user); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorAddAuthLog, Err: errors.Wrap(err, "Unable to add auth log")} + return "", errors.Wrap(err, "unable to add auth log") } userId = user.ID.Hex() } else { @@ -219,7 +220,7 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm } if err := m.session.Set(ctx, loginRememberKey, form.Remember); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error saving session")} + return "", errors.Wrap(err, "error saving session") } // TODO: Add MFA cases @@ -230,7 +231,7 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm Body: &models2.HandledLoginRequest{Subject: &userId, Remember: form.Remember, RememberFor: 0}, }) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorPasswordIncorrect, Err: errors.Wrap(err, "Unable to accept login challenge")} + return "", errors.Wrap(err, "unable to accept login challenge") } return reqACL.Payload.RedirectTo, nil @@ -353,12 +354,12 @@ func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2Introspec func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, error) { clientId, err := m.session.Get(ctx, clientIdSessionKey) if err != nil { - return false, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get session")} + return false, errors.Wrap(err, "unable to get session") } app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientId.(string))) if err != nil { - return false, &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} + return false, errors.Wrap(err, "unable to load application") } if app.UniqueUsernames == false { @@ -367,40 +368,40 @@ func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, ok, err := m.userService.IsUsernameFree(username, app.ID) if err != nil { - return false, &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "unable check username availability")} + return false, errors.Wrap(err, "unable check username availability") } return ok, nil } -func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) (string, *models.GeneralError) { +func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) (string, error) { if err := m.session.Set(ctx, loginRememberKey, form.Remember); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error saving session")} + return "", errors.Wrap(err, "error saving session") } clientId, err := m.session.Get(ctx, clientIdSessionKey) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get session")} + return "", errors.Wrap(err, "unable to get session") } app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientId.(string))) if err != nil { - return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} + return "", errors.Wrap(err, "unable to load application") } if app.UniqueUsernames { free, err := m.userService.IsUsernameFree(form.Username, app.ID) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to check username availability")} + return "", errors.Wrap(err, "Unable to check username availability") } if !free { - return "", &models.GeneralError{Code: "username_taken", Message: models.ErrorUsernameTaken, Err: errors.New(models.ErrorUsernameTaken)} + return "", apierror.UsernameTaken } } if false == validator.IsPasswordValid(app, form.Password) { - return "", &models.GeneralError{Code: "password", Message: models.ErrorPasswordIncorrect, Err: errors.New(models.ErrorPasswordIncorrect)} + return "", apierror.WeakPassword } encryptedPassword := "" @@ -413,24 +414,24 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Context: ctx.Request().Context(), Challenge: form.Challenge}) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorLoginChallenge, Err: errors.Wrap(err, "Unable to get client from login request")} + return "", apierror.InvalidChallenge } if req.Payload.Client.ClientID != clientId.(string) { - return "", &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Client ID is incorrect")} + return "", errors.Wrap(err, "client ID is incorrect") } ipc := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) if ipc == nil { - return "", &models.GeneralError{Code: "client_id", Message: models.ErrorProviderIdIncorrect, Err: errors.New("Unable to get identity provider")} + return "", errors.New("unable to get identity provider") } userIdentity, err := m.userIdentityService.Get(app, ipc, form.Email) if err == nil { - return "", &models.GeneralError{Code: "email", Message: models.ErrorLoginIncorrect, Err: errors.Wrap(err, "Unable to get user with identity for application")} + return "", apierror.EmailRegistered } if err := t.Wait(); err != nil { - return "", &models.GeneralError{Code: "password", Message: models.ErrorCryptPassword, Err: errors.Wrap(err, "Unable to crypt password")} + return "", errors.Wrap(err, "unable to crypt password") } user := &models.User{ @@ -449,7 +450,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( } if err := m.userService.Create(user); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorCreateUser, Err: errors.Wrap(err, "Unable to create user")} + return "", errors.Wrap(err, "unable to create user") } userIdentity = &models.UserIdentity{ @@ -464,17 +465,17 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( UpdatedAt: time.Now(), } if err := m.userIdentityService.Create(userIdentity); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorCreateUserIdentity, Err: errors.Wrap(err, "Unable to create user identity")} + return "", errors.Wrap(err, "unable to create user identity") } if err := m.authLogService.Add(ctx.RealIP(), ctx.Request().UserAgent(), user); err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorAddAuthLog, Err: errors.Wrap(err, "Unable to add auth log")} + return "", errors.Wrap(err, "unable to add auth log") } userId := user.ID.Hex() reqACL, err := m.r.HydraAdminApi().AcceptLoginRequest(&admin.AcceptLoginRequestParams{Context: ctx.Request().Context(), Challenge: form.Challenge, Body: &models2.HandledLoginRequest{Subject: &userId}}) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to accept login challenge")} + return "", errors.Wrap(err, "unable to accept login challenge") } return reqACL.Payload.RedirectTo, nil From 890459b6cf65d5fcc7c8e457851e40011c3b64e4 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 11 Feb 2020 09:29:10 +0300 Subject: [PATCH 036/251] fix tests --- pkg/manager/oauth2.go | 2 +- pkg/manager/oauth2_test.go | 99 ++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 49 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 66029d5..d1d804b 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -417,7 +417,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return "", apierror.InvalidChallenge } if req.Payload.Client.ClientID != clientId.(string) { - return "", errors.Wrap(err, "client ID is incorrect") + return "", errors.New("client ID is incorrect") } ipc := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index ea7f248..5221318 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -1,6 +1,7 @@ package manager import ( + "fmt" "testing" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" @@ -274,8 +275,8 @@ func TestAuthReturnErrorWithUnableToGetLoginRequest(t *testing.T) { m := &OauthManager{r: r} _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorLoginChallenge, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorLoginChallenge, err.Message) } func TestAuthReturnErrorWithIncorrectToken(t *testing.T) { @@ -291,8 +292,8 @@ func TestAuthReturnErrorWithIncorrectToken(t *testing.T) { m := &OauthManager{r: r} _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Token: "invalid_auth_token"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorCannotUseToken, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorCannotUseToken, err.Message) } func TestAuthReturnErrorWithIncorrectClient(t *testing.T) { @@ -311,8 +312,8 @@ func TestAuthReturnErrorWithIncorrectClient(t *testing.T) { m := &OauthManager{r: r} _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge"}) assert.NotNil(t, err) - assert.Equal(t, "client_id", err.Code) - assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) + // assert.Equal(t, "client_id", err.Code) + // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) } func TestAuthReturnErrorWithUnavailableIdentityProvider(t *testing.T) { @@ -336,8 +337,8 @@ func TestAuthReturnErrorWithUnavailableIdentityProvider(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge"}) assert.NotNil(t, err) - assert.Equal(t, "client_id", err.Code) - assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) + // assert.Equal(t, "client_id", err.Code) + // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) } func TestAuthReturnErrorWithUnavailableUserIdentity(t *testing.T) { @@ -364,8 +365,8 @@ func TestAuthReturnErrorWithUnavailableUserIdentity(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Email: "invalid_email"}) assert.NotNil(t, err) - assert.Equal(t, "email", err.Code) - assert.Equal(t, models.ErrorLoginIncorrect, err.Message) + // assert.Equal(t, "email", err.Code) + // assert.Equal(t, models.ErrorLoginIncorrect, err.Message) } func TestAuthReturnErrorWithComparePassword(t *testing.T) { @@ -394,8 +395,8 @@ func TestAuthReturnErrorWithComparePassword(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Email: "email", Password: "1234"}) assert.NotNil(t, err) - assert.Equal(t, "password", err.Code) - assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) + // assert.Equal(t, "password", err.Code) + // assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) } func TestAuthReturnErrorWithUnableToGetUser(t *testing.T) { @@ -429,8 +430,8 @@ func TestAuthReturnErrorWithUnableToGetUser(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Email: "email", Password: "1234"}) assert.NotNil(t, err) - assert.Equal(t, "email", err.Code) - assert.Equal(t, models.ErrorLoginIncorrect, err.Message) + // assert.Equal(t, "email", err.Code) + // assert.Equal(t, models.ErrorLoginIncorrect, err.Message) } func TestAuthReturnErrorWithUnableToUpdateUser(t *testing.T) { @@ -465,8 +466,8 @@ func TestAuthReturnErrorWithUnableToUpdateUser(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Email: "email", Password: "1234"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorUpdateUser, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorUpdateUser, err.Message) } func TestAuthReturnErrorWithUnableToAddAuthLog(t *testing.T) { @@ -504,8 +505,8 @@ func TestAuthReturnErrorWithUnableToAddAuthLog(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Email: "email", Password: "1234"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorAddAuthLog, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorAddAuthLog, err.Message) } func TestAuthReturnErrorWithUnableToSetSessionRemember(t *testing.T) { @@ -523,8 +524,8 @@ func TestAuthReturnErrorWithUnableToSetSessionRemember(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Remember: true, PreviousLogin: "subj"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorUnknownError, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorUnknownError, err.Message) } func TestAuthReturnErrorWithUnableToAcceptLoginRequest(t *testing.T) { @@ -543,8 +544,8 @@ func TestAuthReturnErrorWithUnableToAcceptLoginRequest(t *testing.T) { } _, err := m.Auth(getContext(), &models.Oauth2LoginSubmitForm{Challenge: "login_challenge", Remember: true, PreviousLogin: "subj"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) } func TestAuthReturnUrlToConsentRequest(t *testing.T) { @@ -796,8 +797,8 @@ func TestSignUpReturnErrorWithUnableToSetRememberToSession(t *testing.T) { m := &OauthManager{session: s} _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorUnknownError, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorUnknownError, err.Message) } func TestSignUpReturnErrorWithUnableToGetClientFromSession(t *testing.T) { @@ -815,8 +816,8 @@ func TestSignUpReturnErrorWithUnableToGetClientFromSession(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorUnknownError, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorUnknownError, err.Message) } func TestSignUpReturnErrorWithUnableToGetApplication(t *testing.T) { @@ -835,8 +836,8 @@ func TestSignUpReturnErrorWithUnableToGetApplication(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) assert.NotNil(t, err) - assert.Equal(t, "client_id", err.Code) - assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) + // assert.Equal(t, "client_id", err.Code) + // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) } func TestSignUpReturnErrorWithInvalidPassword(t *testing.T) { @@ -856,8 +857,8 @@ func TestSignUpReturnErrorWithInvalidPassword(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "1"}) assert.NotNil(t, err) - assert.Equal(t, "password", err.Code) - assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) + // assert.Equal(t, "password", err.Code) + // assert.Equal(t, models.ErrorPasswordIncorrect, err.Message) } func TestSignUpReturnErrorWithUnableToGetLoginChallenge(t *testing.T) { @@ -880,8 +881,8 @@ func TestSignUpReturnErrorWithUnableToGetLoginChallenge(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorLoginChallenge, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorLoginChallenge, err.Message) } func TestSignUpReturnErrorWithDifferentClientId(t *testing.T) { @@ -903,9 +904,11 @@ func TestSignUpReturnErrorWithDifferentClientId(t *testing.T) { session: s, } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) + + fmt.Println(err) assert.NotNil(t, err) - assert.Equal(t, "client_id", err.Code) - assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) + // assert.Equal(t, "client_id", err.Code) + // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) } func TestSignUpReturnErrorWithUnavailableIdentityProvider(t *testing.T) { @@ -932,8 +935,8 @@ func TestSignUpReturnErrorWithUnavailableIdentityProvider(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) assert.NotNil(t, err) - assert.Equal(t, "client_id", err.Code) - assert.Equal(t, models.ErrorProviderIdIncorrect, err.Message) + // assert.Equal(t, "client_id", err.Code) + // assert.Equal(t, models.ErrorProviderIdIncorrect, err.Message) } func TestSignUpReturnErrorWithUnableToGetUserIdentity(t *testing.T) { @@ -963,8 +966,8 @@ func TestSignUpReturnErrorWithUnableToGetUserIdentity(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "email", err.Code) - assert.Equal(t, models.ErrorLoginIncorrect, err.Message) + // assert.Equal(t, "email", err.Code) + // assert.Equal(t, models.ErrorLoginIncorrect, err.Message) } func TestSignUpReturnErrorWithEncryptPassword(t *testing.T) { @@ -994,8 +997,8 @@ func TestSignUpReturnErrorWithEncryptPassword(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "password", err.Code) - assert.Equal(t, models.ErrorCryptPassword, err.Message) + // assert.Equal(t, "password", err.Code) + // assert.Equal(t, models.ErrorCryptPassword, err.Message) } func TestSignUpReturnErrorWithUnableToCreateUser(t *testing.T) { @@ -1028,8 +1031,8 @@ func TestSignUpReturnErrorWithUnableToCreateUser(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorCreateUser, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorCreateUser, err.Message) } func TestSignUpReturnErrorWithUnableToCreateUserIdentity(t *testing.T) { @@ -1063,8 +1066,8 @@ func TestSignUpReturnErrorWithUnableToCreateUserIdentity(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorCreateUserIdentity, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorCreateUserIdentity, err.Message) } func TestSignUpReturnErrorWithUnableToAddAuthLog(t *testing.T) { @@ -1101,8 +1104,8 @@ func TestSignUpReturnErrorWithUnableToAddAuthLog(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorAddAuthLog, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorAddAuthLog, err.Message) } func TestSignUpReturnErrorWithUnableToAcceptLoginChallenge(t *testing.T) { @@ -1140,8 +1143,8 @@ func TestSignUpReturnErrorWithUnableToAcceptLoginChallenge(t *testing.T) { } _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge", Email: "email"}) assert.NotNil(t, err) - assert.Equal(t, "common", err.Code) - assert.Equal(t, models.ErrorUnknownError, err.Message) + // assert.Equal(t, "common", err.Code) + // assert.Equal(t, models.ErrorUnknownError, err.Message) } func TestSignUpReturnUrlOnSuccessResponse(t *testing.T) { From e57fc05a2a3fe2107feb78fd639593b097f9da5c Mon Sep 17 00:00:00 2001 From: Serge Date: Thu, 13 Feb 2020 15:10:00 +0500 Subject: [PATCH 037/251] fix: fixed error messages --- pkg/api/apierror/error.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/apierror/error.go b/pkg/api/apierror/error.go index 32203d8..4614f70 100644 --- a/pkg/api/apierror/error.go +++ b/pkg/api/apierror/error.go @@ -27,8 +27,8 @@ var ( InvalidChallenge = Error{1003, "invalid_challenge", http.StatusBadRequest} InvalidToken = Error{1004, "invalid_token", http.StatusBadRequest} InvalidClient = Error{1005, "invalid_client", http.StatusBadRequest} - InvalidEmail = Error{1006, "invalid_credentials", http.StatusBadRequest} - InvalidPassword = Error{1007, "invalid_credentials", http.StatusBadRequest} + InvalidEmail = Error{1006, "invalid_email", http.StatusBadRequest} + InvalidPassword = Error{1007, "invalid_password", http.StatusBadRequest} UsernameTaken = Error{1008, "username_already_exists", http.StatusBadRequest} WeakPassword = Error{1009, "password_does_not_meet_policy", http.StatusBadRequest} EmailRegistered = Error{1010, "email_already_registered", http.StatusBadRequest} From 5e906a24bc7280ede57e789b0107ee4c16fd7f6a Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Sat, 15 Feb 2020 18:00:16 +0300 Subject: [PATCH 038/251] improve api errors --- go.mod | 19 ------- go.sum | 50 +++++++---------- pkg/api/apierror/api_error.go | 33 +++++++++++ pkg/api/apierror/error.go | 84 ---------------------------- pkg/api/apierror/errors.go | 41 ++++++++++++++ pkg/api/apierror/handler.go | 48 ++++++++++++++++ pkg/api/apierror/handler_test.go | 94 ++++++++++++++++++++++++++++++++ pkg/manager/oauth2.go | 4 +- 8 files changed, 237 insertions(+), 136 deletions(-) create mode 100644 pkg/api/apierror/api_error.go delete mode 100644 pkg/api/apierror/error.go create mode 100644 pkg/api/apierror/errors.go create mode 100644 pkg/api/apierror/handler.go create mode 100644 pkg/api/apierror/handler_test.go diff --git a/go.mod b/go.mod index 4ea53a4..43819ec 100644 --- a/go.mod +++ b/go.mod @@ -3,50 +3,31 @@ module github.com/ProtocolONE/auth1.protocol.one require ( github.com/ProtocolONE/authone-jwt-verifier-golang v0.0.0-20190329122021-aa7178c82afb github.com/ProtocolONE/mfa-service v0.1.1 - github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect - github.com/alicebob/miniredis v2.5.0+incompatible github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/elliotchance/redismock v1.5.1 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/go-openapi/runtime v0.19.0 - github.com/go-openapi/strfmt v0.19.0 - github.com/go-openapi/swag v0.19.0 github.com/go-redis/redis v6.15.2+incompatible - github.com/golang/oauth2 v0.0.0-20181203162652-d668ce993890 - github.com/golang/protobuf v1.3.2 github.com/google/uuid v1.1.1 - github.com/gorilla/securecookie v1.1.1 - github.com/gorilla/sessions v1.1.3 - github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3 - github.com/juju/mgosession v1.0.0 // indirect github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac github.com/kelseyhightower/envconfig v1.3.0 - github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 github.com/labstack/echo/v4 v4.1.14 - github.com/labstack/gommon v0.3.0 github.com/micro/go-micro v1.8.0 github.com/micro/go-plugins v1.2.0 github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 github.com/pkg/errors v0.8.1 - github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.3 - github.com/spf13/viper v1.3.2 github.com/stretchr/testify v1.4.0 github.com/xakep666/mongo-migrate v0.1.0 - github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583 // indirect go.uber.org/zap v1.10.0 golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 gopkg.in/go-playground/validator.v9 v9.29.1 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect - gopkg.in/yaml.v2 v2.2.2 ) replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.5.1 diff --git a/go.sum b/go.sum index 24efb90..d1cc81f 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,6 @@ github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvB github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 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/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= @@ -156,9 +154,7 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -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 v0.0.0-20161109192337-d17a8420c36e/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.0.0-20161110002650-365d370cc145/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= @@ -215,7 +211,6 @@ github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7j github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elliotchance/redismock v1.5.1/go.mod h1:8FFsGWghPUyP7nqj/UYXr2xqd6U2iNMxS4S5+Xadl5A= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.0.0-20180919002855-2137d9196328/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -230,7 +225,9 @@ github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20181003173013-ead4ad1d2727/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +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/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI= @@ -502,6 +499,7 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20181116215533-9bd4a3295021/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/gddo v0.0.0-20190312205958-5a2505f3dbf0/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -509,7 +507,6 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j 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/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:ovBFgdmJqyggKzXS0i5+osE+RsPEbEsUfp2sVCgys1Q= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -528,6 +525,7 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 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.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -595,6 +593,7 @@ github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4 github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -629,6 +628,7 @@ github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0S 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 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v0.0.0-20170202080759-03c5bf6be031/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -663,11 +663,11 @@ github.com/hashicorp/vault v1.1.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAb github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190318174639-195e0e9d07f1/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/hudl/fargo v1.2.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -702,17 +702,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= -github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA= -github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20160818025724-3b7ece48644d/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/loggo v0.0.0-20190212223446-d976af380377/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/mgosession v1.0.0/go.mod h1:4zVjdmPhtQ+tFwByzM8UcGYKEqqiG9TvPArt210VNw4= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= -github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= -github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk= -github.com/juju/version v0.0.0-20160603194958-4ae6172c0062/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U= github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac h1:mIYfqlPcFmuFpKMMMmq+pu7okWEWShiyW2w6/+2qDaY= github.com/juju/zaputil v0.0.0-20190326175239-ef53049637ac/go.mod h1:yGXwCw1C3O7X2kkzB5gky65S4I5a0h4Ylic4xVo5D78= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -727,7 +718,6 @@ github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -766,7 +756,6 @@ github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1 github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= github.com/luna-duclos/instrumentedsql v0.0.0-20190316074304-ecad98b20aec/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= -github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.0-20180911180927-64fcb82c878e/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -795,7 +784,6 @@ github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGD github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= @@ -804,7 +792,6 @@ github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaa github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= @@ -846,6 +833,7 @@ github.com/mitchellh/copystructure v0.0.0-20160804032330-cdac8253d00f/go.mod h1: github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= @@ -876,8 +864,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.2.6/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= github.com/nats-io/jwt v0.2.8/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= +github.com/nats-io/jwt v0.2.12 h1:Y3YLoJey+Q/yMk/1Ig3xhWxYXE7vNSefozkArIcnSlU= github.com/nats-io/jwt v0.2.12/go.mod h1:mQxQ0uHQ9FhEVPIcTSKwx2lqZEpXWWcCgA7R6NrWvvY= github.com/nats-io/nats-server/v2 v2.0.0/go.mod h1:RyVdsHHvY4B6c9pWG+uRLpZ0h0XsqiuKp2XCTurP5LI= +github.com/nats-io/nats-server/v2 v2.0.2 h1:dB1cucvPi3Kgq0H7LbOENHfRf4buy8coAP48CjSvgm8= github.com/nats-io/nats-server/v2 v2.0.2/go.mod h1:sk9mvTwGZiqHrkA12dw2r6LKmPYPkw15tB8haEsvxo8= github.com/nats-io/nats-streaming-server v0.15.1/go.mod h1:bJ1+2CS8MqvkGfr/NwnCF+Lw6aLnL3F5kenM8bZmdCw= github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= @@ -901,11 +891,13 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -930,6 +922,7 @@ github.com/ory/x v0.0.49/go.mod h1:LVQf17Z8SK/y0H0ewDuIqJLDCjQ2eOIfQT5l0LH53ls= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -1121,7 +1114,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= -github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1152,7 +1144,6 @@ gocloud.dev v0.15.0/go.mod h1:ShXCyJaGrJu9y/7a6+DSCyBb9MFGZ1P5wwPa0Wu6w34= gocloud.dev/pubsub/rabbitpubsub v0.15.0/go.mod h1:LGg5Acwcpry+GeLNaA01xm0Ij43YUis6kht2qRX2tg0= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4= -golang.org/x/crypto v0.0.0-20161221235747-f6b343c37ca8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1191,6 +1182,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL 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-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190718202018-cfdd5522f6f6 h1:1xlTfQXUyQvvbx4TFsXRgoj9r0YUwcqq9XGX9u9OODU= golang.org/x/exp v0.0.0-20190718202018-cfdd5522f6f6/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1268,8 +1260,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20161012001920-9bb9f0998d48/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1300,7 +1292,6 @@ golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3/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-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1448,14 +1439,16 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.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.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= @@ -1470,12 +1463,9 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eR gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/juju/names.v2 v2.0.0-20180621093930-fd59336b4621/go.mod h1:XXa/v5qG1IsStRg5KTE8JkDMndoDMOKH1YYw0jSUWaM= gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= -gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= gopkg.in/redis.v3 v3.6.4/go.mod h1:6XeGv/CrsUFDU9aVbUdNykN7k1zVmoeg83KC9RbQfiU= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1489,13 +1479,11 @@ gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzE gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/tomb.v2 v2.0.0-20140626144623-14b3d72120e8/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/pkg/api/apierror/api_error.go b/pkg/api/apierror/api_error.go new file mode 100644 index 0000000..91cb4e5 --- /dev/null +++ b/pkg/api/apierror/api_error.go @@ -0,0 +1,33 @@ +package apierror + +type APIError struct { + Code string `json:"code"` + Message string `json:"error"` + Status int `json:"-"` + Param string `json:"param,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +var _ error = &APIError{} // assert error interface + +func NewAPIError(code string, message string, status int) *APIError { + return &APIError{ + Message: message, + Code: code, + Status: status, + } +} + +func (e *APIError) Error() string { return e.Code + " " + e.Message } + +func (e *APIError) WithParam(param string) *APIError { + var c = *e + c.Param = param + return &c +} + +func (e *APIError) WithData(data interface{}) *APIError { + var c = *e + c.Data = data + return &c +} diff --git a/pkg/api/apierror/error.go b/pkg/api/apierror/error.go deleted file mode 100644 index 32203d8..0000000 --- a/pkg/api/apierror/error.go +++ /dev/null @@ -1,84 +0,0 @@ -package apierror - -import ( - "fmt" - "net/http" - - "github.com/labstack/echo/v4" -) - -type Error struct { - Code int - Message string - Status uint16 -} - -func (e Error) Error() string { - return e.Message -} - -const ErrorPrefix = "errors.one.protocol.auth1." - -var ( - unknown = Error{1000, "unknown", http.StatusInternalServerError} - invalidRequest = Error{1001, "invalid_request", http.StatusBadRequest} - invalidParameters = Error{1002, "invalid_parameters", http.StatusBadRequest} - - InvalidChallenge = Error{1003, "invalid_challenge", http.StatusBadRequest} - InvalidToken = Error{1004, "invalid_token", http.StatusBadRequest} - InvalidClient = Error{1005, "invalid_client", http.StatusBadRequest} - InvalidEmail = Error{1006, "invalid_credentials", http.StatusBadRequest} - InvalidPassword = Error{1007, "invalid_credentials", http.StatusBadRequest} - UsernameTaken = Error{1008, "username_already_exists", http.StatusBadRequest} - WeakPassword = Error{1009, "password_does_not_meet_policy", http.StatusBadRequest} - EmailRegistered = Error{1010, "email_already_registered", http.StatusBadRequest} -) - -func Unknown(err error) error { - return invalidRequest -} - -func InvalidRequest(err error) error { - return invalidRequest -} - -func InvalidParameters(err error) error { - return invalidParameters -} - -type Response struct { - Error string `json:"error"` - Code string `json:"code"` - RequestID string `json:"request_id"` -} - -func Handler(err error, ctx echo.Context) { - rid := ctx.Response().Header().Get(echo.HeaderXRequestID) - - var e Error - if x, ok := err.(Error); ok { - e = x - } else { - ctx.Logger().Error(err) - e = unknown - } - - var resp = Response{ - Error: ErrorPrefix + e.Message, - Code: fmt.Sprintf("AU-%d", e.Code), - RequestID: rid, - } - var code = int(e.Status) - - // Send response - if !ctx.Response().Committed { - if ctx.Request().Method == http.MethodHead { - err = ctx.NoContent(code) - } else { - err = ctx.JSON(code, resp) - } - if err != nil { - ctx.Logger().Error(err) - } - } -} diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go new file mode 100644 index 0000000..eca658b --- /dev/null +++ b/pkg/api/apierror/errors.go @@ -0,0 +1,41 @@ +package apierror + +import ( + "fmt" + "net/http" +) + +const ( + ErrorPrefix = "errors.one.protocol.auth1." + ServicePrefix = "AU" +) + +var ( + unknown = New(1000, "unknown", http.StatusInternalServerError) + invalidRequest = New(1001, "invalid_request", http.StatusBadRequest) + invalidParameters = New(1002, "invalid_parameters", http.StatusBadRequest) + InvalidChallenge = New(1003, "invalid_challenge", http.StatusBadRequest).WithParam("challenge") + InvalidToken = New(1004, "invalid_token", http.StatusBadRequest).WithParam("token") + InvalidClient = New(1005, "invalid_client", http.StatusBadRequest) + EmailNotFound = New(1006, "email_not_found", http.StatusBadRequest).WithParam("email") + InvalidCredentials = New(1007, "invalid_credentials", http.StatusBadRequest) + UsernameTaken = New(1008, "username_already_exists", http.StatusBadRequest).WithParam("username") + WeakPassword = New(1009, "password_does_not_meet_policy", http.StatusBadRequest).WithParam("password") + EmailRegistered = New(1010, "email_already_registered", http.StatusBadRequest).WithParam("email") +) + +func New(code int, message string, status int) *APIError { + return NewAPIError(fmt.Sprintf("%s-%d", ServicePrefix, code), ErrorPrefix+message, status) +} + +func Unknown(err error) error { + return unknown +} + +func InvalidRequest(err error) error { + return invalidRequest +} + +func InvalidParameters(err error) error { + return invalidParameters +} diff --git a/pkg/api/apierror/handler.go b/pkg/api/apierror/handler.go new file mode 100644 index 0000000..b22bbdb --- /dev/null +++ b/pkg/api/apierror/handler.go @@ -0,0 +1,48 @@ +package apierror + +import ( + "net/http" + + "errors" + + "github.com/labstack/echo/v4" +) + +// Response represents json response for api errors +type Response struct { + *APIError + RequestID string `json:"request_id,omitempty"` +} + +// Handler represents echo error handler for api +func Handler(err error, ctx echo.Context) { + if ctx.Response().Committed { + ctx.Logger().Error("response already commited", err) + return + } + + var e *APIError + if !errors.As(err, &e) { + ctx.Logger().Error(err) + e = unknown + } + + if err := resp(ctx, e); err != nil { + ctx.Logger().Error(err) + } +} + +// resp generates server response for error +func resp(ctx echo.Context, e *APIError) error { + var code = e.Status + if ctx.Request().Method == http.MethodHead { + return ctx.NoContent(code) + } + + rid := ctx.Response().Header().Get(echo.HeaderXRequestID) + var resp = Response{ + RequestID: rid, + APIError: e, + } + return ctx.JSON(code, resp) +} diff --git a/pkg/api/apierror/handler_test.go b/pkg/api/apierror/handler_test.go new file mode 100644 index 0000000..e311bba --- /dev/null +++ b/pkg/api/apierror/handler_test.go @@ -0,0 +1,94 @@ +package apierror + +import ( + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/stretchr/testify/assert" +) + +func TestHandleUnknownError(t *testing.T) { + // Arrange + var unkErrorJSON = `{"code":"AU-1000","error":"errors.one.protocol.auth1.unknown"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodPost, "/", nil), rec) + + // Act + c.Error(errors.New("some new error")) + + // Assert + assert.Equal(t, http.StatusInternalServerError, rec.Code) + assert.Equal(t, unkErrorJSON, rec.Body.String()) +} + +func TestHandleAPIError(t *testing.T) { + // Arrange + var testErrorJSON = `{"code":"AU-100","error":"errors.one.protocol.auth1.test"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodPost, "/", nil), rec) + + // Act + c.Error(New(100, "test", http.StatusTeapot)) + + // Assert + assert.Equal(t, http.StatusTeapot, rec.Code) + assert.Equal(t, testErrorJSON, rec.Body.String()) +} + +func TestHandleAPIErrorWithParam(t *testing.T) { + // Arrange + var testErrorJSON = `{"code":"AU-100","error":"errors.one.protocol.auth1.test","param":"some"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodPost, "/", nil), rec) + + // Act + c.Error(New(100, "test", http.StatusTeapot).WithParam("some")) + + // Assert + assert.Equal(t, http.StatusTeapot, rec.Code) + assert.Equal(t, testErrorJSON, rec.Body.String()) +} + +func TestHandleErrorWithRequestID(t *testing.T) { + // Arrange + var testErrorJSON = `{"code":"AU-100","error":"errors.one.protocol.auth1.test","request_id":"request-id"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + // e.Use(middleware.RequestID()) + req := httptest.NewRequest(http.MethodPost, "/", nil) + req.Header.Add(echo.HeaderXRequestID, "request-id") + c := e.NewContext(req, rec) + + // Act + middleware.RequestID()(echo.NotFoundHandler)(c) // apply middleware + c.Error(New(100, "test", http.StatusTeapot)) + + // Assert + assert.Equal(t, http.StatusTeapot, rec.Code) + assert.Equal(t, testErrorJSON, rec.Body.String()) +} + +func TestHandleErrorMethodHEAD(t *testing.T) { + // Arrange + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodHead, "/", nil), rec) + + // Act + c.Error(New(100, "test", http.StatusTeapot)) + + // Assert + assert.Equal(t, http.StatusTeapot, rec.Code) + assert.Equal(t, "", rec.Body.String()) +} diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index d1d804b..1af5844 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -192,12 +192,12 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm userIdentity, err = m.userIdentityService.Get(app, ipc, form.Email) if err != nil { - return "", apierror.InvalidEmail + return "", apierror.EmailNotFound } encryptor := models.NewBcryptEncryptor(&models.CryptConfig{Cost: app.PasswordSettings.BcryptCost}) if err := encryptor.Compare(userIdentity.Credential, form.Password); err != nil { - return "", apierror.InvalidPassword + return "", apierror.InvalidCredentials } } From dbe6ae5fa283d4319382ed0b93820242355163d4 Mon Sep 17 00:00:00 2001 From: Behuamuh Date: Wed, 12 Feb 2020 06:21:43 +0300 Subject: [PATCH 039/251] Added template --- public/templates/email/change_password_2.html | 386 ++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 public/templates/email/change_password_2.html diff --git a/public/templates/email/change_password_2.html b/public/templates/email/change_password_2.html new file mode 100644 index 0000000..336f723 --- /dev/null +++ b/public/templates/email/change_password_2.html @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 39920c41120780d3f8a6b5cab126b60bbd321818 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 17 Feb 2020 12:05:28 +0300 Subject: [PATCH 040/251] disable pull request deploys --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6cda44b..638849b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ cache: stages: - test - name: deploy - if: branch IN (master, develop) + if: branch IN (master, develop) AND type != pull_request jobs: include: From 10ee378cce17be4c09c510a61badf05bd4bf7083 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 17 Feb 2020 13:13:08 +0300 Subject: [PATCH 041/251] open access to openid-configuration --- .helm/templates/ingress.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 5c95ef3..841e46f 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -54,3 +54,7 @@ spec: backend: serviceName: {{ $hydraSvc }} servicePort: 4444 + - path: /.well-known/openid-configuration + backend: + serviceName: {{ $hydraSvc }} + servicePort: 4444 From 93cec04320dc76909c3e900b07874819843b9815 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 17 Feb 2020 13:18:51 +0300 Subject: [PATCH 042/251] move captha to api --- pkg/api/captcha.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index e19aa6f..6d47981 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -15,7 +15,7 @@ func InitCaptcha(cfg *Server) error { recaptcha: cfg.Recaptcha, session: service.NewSessionService(cfg.SessionConfig.Name), } - cfg.Echo.Group("/captcha"). + cfg.Echo.Group("/api/captcha"). POST("/re3", c.verify) return nil From be3dcd61cd8f6cb1e5f5f5b1e4083218e33b9aec Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 17 Feb 2020 14:46:25 +0300 Subject: [PATCH 043/251] fix csrf, not found and method not allowed errors --- go.mod | 1 + pkg/api/apierror/errors.go | 10 +- pkg/api/apierror/handler.go | 11 +- pkg/api/csrf.go | 217 ++++++++++++++++++++++++++++++++++++ pkg/api/server.go | 2 +- 5 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 pkg/api/csrf.go diff --git a/go.mod b/go.mod index 43819ec..9bcfb70 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/kelseyhightower/envconfig v1.3.0 github.com/labstack/echo-contrib v0.0.0-20190220224852-7fa08ffe9442 github.com/labstack/echo/v4 v4.1.14 + github.com/labstack/gommon v0.3.0 github.com/micro/go-micro v1.8.0 github.com/micro/go-plugins v1.2.0 github.com/ory/hydra v0.0.0-20190418080013-9c6e4c120c12 diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go index eca658b..44c89f0 100644 --- a/pkg/api/apierror/errors.go +++ b/pkg/api/apierror/errors.go @@ -22,20 +22,24 @@ var ( UsernameTaken = New(1008, "username_already_exists", http.StatusBadRequest).WithParam("username") WeakPassword = New(1009, "password_does_not_meet_policy", http.StatusBadRequest).WithParam("password") EmailRegistered = New(1010, "email_already_registered", http.StatusBadRequest).WithParam("email") + MissingCSRFToken = New(1011, "missing_csrf_token", http.StatusBadRequest).WithParam("x-xsrf-token") + InvalidCSRFToken = New(1012, "missing_csrf_token", http.StatusForbidden).WithParam("x-xsrf-token") + MethodNotAllowed = New(1013, "method_not_allowed", http.StatusMethodNotAllowed) + NotFound = New(1014, "not_found", http.StatusNotFound) ) func New(code int, message string, status int) *APIError { return NewAPIError(fmt.Sprintf("%s-%d", ServicePrefix, code), ErrorPrefix+message, status) } -func Unknown(err error) error { +func Unknown(err error) *APIError { return unknown } -func InvalidRequest(err error) error { +func InvalidRequest(err error) *APIError { return invalidRequest } -func InvalidParameters(err error) error { +func InvalidParameters(err error) *APIError { return invalidParameters } diff --git a/pkg/api/apierror/handler.go b/pkg/api/apierror/handler.go index b22bbdb..6f26b81 100644 --- a/pkg/api/apierror/handler.go +++ b/pkg/api/apierror/handler.go @@ -23,8 +23,15 @@ func Handler(err error, ctx echo.Context) { var e *APIError if !errors.As(err, &e) { - ctx.Logger().Error(err) - e = unknown + switch err { + case echo.ErrMethodNotAllowed: + e = MethodNotAllowed + case echo.ErrNotFound: + e = NotFound + default: + ctx.Logger().Error(err) + e = Unknown(err) + } } if err := resp(ctx, e); err != nil { diff --git a/pkg/api/csrf.go b/pkg/api/csrf.go new file mode 100644 index 0000000..bdc357c --- /dev/null +++ b/pkg/api/csrf.go @@ -0,0 +1,217 @@ +package api + +// ORIGINAL https://github.com/labstack/echo/blob/v4.1.14/middleware/csrf.go +// modified errors to match our errors conventions + +import ( + "crypto/subtle" + "errors" + "net/http" + "strings" + "time" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/labstack/gommon/random" +) + +type ( + // CSRFConfig defines the config for CSRF middleware. + CSRFConfig struct { + // Skipper defines a function to skip middleware. + Skipper middleware.Skipper + + // TokenLength is the length of the generated token. + TokenLength uint8 `yaml:"token_length"` + // Optional. Default value 32. + + // TokenLookup is a string in the form of ":" that is used + // to extract token from the request. + // Optional. Default value "header:X-CSRF-Token". + // Possible values: + // - "header:" + // - "form:" + // - "query:" + TokenLookup string `yaml:"token_lookup"` + + // Context key to store generated CSRF token into context. + // Optional. Default value "csrf". + ContextKey string `yaml:"context_key"` + + // Name of the CSRF cookie. This cookie will store CSRF token. + // Optional. Default value "csrf". + CookieName string `yaml:"cookie_name"` + + // Domain of the CSRF cookie. + // Optional. Default value none. + CookieDomain string `yaml:"cookie_domain"` + + // Path of the CSRF cookie. + // Optional. Default value none. + CookiePath string `yaml:"cookie_path"` + + // Max age (in seconds) of the CSRF cookie. + // Optional. Default value 86400 (24hr). + CookieMaxAge int `yaml:"cookie_max_age"` + + // Indicates if CSRF cookie is secure. + // Optional. Default value false. + CookieSecure bool `yaml:"cookie_secure"` + + // Indicates if CSRF cookie is HTTP only. + // Optional. Default value false. + CookieHTTPOnly bool `yaml:"cookie_http_only"` + } + + // csrfTokenExtractor defines a function that takes `echo.Context` and returns + // either a token or an error. + csrfTokenExtractor func(echo.Context) (string, error) +) + +var ( + // DefaultCSRFConfig is the default CSRF middleware config. + DefaultCSRFConfig = CSRFConfig{ + Skipper: middleware.DefaultSkipper, + TokenLength: 32, + TokenLookup: "header:" + echo.HeaderXCSRFToken, + ContextKey: "csrf", + CookieName: "_csrf", + CookieMaxAge: 86400, + } +) + +// CSRF returns a Cross-Site Request Forgery (CSRF) middleware. +// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery +func CSRF() echo.MiddlewareFunc { + c := DefaultCSRFConfig + return CSRFWithConfig(c) +} + +// CSRFWithConfig returns a CSRF middleware with config. +// See `CSRF()`. +func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc { + // Defaults + if config.Skipper == nil { + config.Skipper = DefaultCSRFConfig.Skipper + } + if config.TokenLength == 0 { + config.TokenLength = DefaultCSRFConfig.TokenLength + } + if config.TokenLookup == "" { + config.TokenLookup = DefaultCSRFConfig.TokenLookup + } + if config.ContextKey == "" { + config.ContextKey = DefaultCSRFConfig.ContextKey + } + if config.CookieName == "" { + config.CookieName = DefaultCSRFConfig.CookieName + } + if config.CookieMaxAge == 0 { + config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge + } + + // Initialize + parts := strings.Split(config.TokenLookup, ":") + extractor := csrfTokenFromHeader(parts[1]) + switch parts[0] { + case "form": + extractor = csrfTokenFromForm(parts[1]) + case "query": + extractor = csrfTokenFromQuery(parts[1]) + } + + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + if config.Skipper(c) { + return next(c) + } + + req := c.Request() + k, err := c.Cookie(config.CookieName) + token := "" + + // Generate token + if err != nil { + token = random.String(config.TokenLength) + } else { + // Reuse token + token = k.Value + } + + switch req.Method { + case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace: + default: + // Validate token only for requests which are not defined as 'safe' by RFC7231 + clientToken, err := extractor(c) + if err != nil { + // return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + return apierror.MissingCSRFToken + } + if !validateCSRFToken(token, clientToken) { + // return echo.NewHTTPError(http.StatusForbidden, "invalid csrf token") + return apierror.InvalidCSRFToken + } + } + + // Set CSRF cookie + cookie := new(http.Cookie) + cookie.Name = config.CookieName + cookie.Value = token + if config.CookiePath != "" { + cookie.Path = config.CookiePath + } + if config.CookieDomain != "" { + cookie.Domain = config.CookieDomain + } + cookie.Expires = time.Now().Add(time.Duration(config.CookieMaxAge) * time.Second) + cookie.Secure = config.CookieSecure + cookie.HttpOnly = config.CookieHTTPOnly + c.SetCookie(cookie) + + // Store token in the context + c.Set(config.ContextKey, token) + + // Protect clients from caching the response + c.Response().Header().Add(echo.HeaderVary, echo.HeaderCookie) + + return next(c) + } + } +} + +// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the +// provided request header. +func csrfTokenFromHeader(header string) csrfTokenExtractor { + return func(c echo.Context) (string, error) { + return c.Request().Header.Get(header), nil + } +} + +// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the +// provided form parameter. +func csrfTokenFromForm(param string) csrfTokenExtractor { + return func(c echo.Context) (string, error) { + token := c.FormValue(param) + if token == "" { + return "", errors.New("missing csrf token in the form parameter") + } + return token, nil + } +} + +// csrfTokenFromQuery returns a `csrfTokenExtractor` that extracts token from the +// provided query parameter. +func csrfTokenFromQuery(param string) csrfTokenExtractor { + return func(c echo.Context) (string, error) { + token := c.QueryParam(param) + if token == "" { + return "", errors.New("missing csrf token in the query string") + } + return token, nil + } +} + +func validateCSRFToken(token, clientToken string) bool { + return subtle.ConstantTimeCompare([]byte(token), []byte(clientToken)) == 1 +} diff --git a/pkg/api/server.go b/pkg/api/server.go index 88f49b5..41edd2d 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -137,7 +137,7 @@ func NewServer(c *ServerConfig) (*Server, error) { AllowCredentials: c.ApiConfig.AllowCredentials, AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete, http.MethodOptions}, })) - s.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ + s.Use(CSRFWithConfig(CSRFConfig{ TokenLookup: "header:X-XSRF-TOKEN", CookieName: "_csrf", Skipper: csrfSkipper, From 5cd693f8068ab400e2a5ac10a662b5068c6f111f Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 17 Feb 2020 15:01:58 +0300 Subject: [PATCH 044/251] test new errors --- pkg/api/apierror/errors.go | 2 +- pkg/api/apierror/handler_test.go | 32 ++++++++++++++++++++ pkg/api/csrf_test.go | 52 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 pkg/api/csrf_test.go diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go index 44c89f0..c97e5b2 100644 --- a/pkg/api/apierror/errors.go +++ b/pkg/api/apierror/errors.go @@ -23,7 +23,7 @@ var ( WeakPassword = New(1009, "password_does_not_meet_policy", http.StatusBadRequest).WithParam("password") EmailRegistered = New(1010, "email_already_registered", http.StatusBadRequest).WithParam("email") MissingCSRFToken = New(1011, "missing_csrf_token", http.StatusBadRequest).WithParam("x-xsrf-token") - InvalidCSRFToken = New(1012, "missing_csrf_token", http.StatusForbidden).WithParam("x-xsrf-token") + InvalidCSRFToken = New(1012, "invalid_csrf_token", http.StatusForbidden).WithParam("x-xsrf-token") MethodNotAllowed = New(1013, "method_not_allowed", http.StatusMethodNotAllowed) NotFound = New(1014, "not_found", http.StatusNotFound) ) diff --git a/pkg/api/apierror/handler_test.go b/pkg/api/apierror/handler_test.go index e311bba..7ce01d7 100644 --- a/pkg/api/apierror/handler_test.go +++ b/pkg/api/apierror/handler_test.go @@ -11,6 +11,38 @@ import ( "github.com/stretchr/testify/assert" ) +func TestHandleNotFoundError(t *testing.T) { + // Arrange + var errorJSON = `{"code":"AU-1014","error":"errors.one.protocol.auth1.not_found"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodPost, "/", nil), rec) + + // Act + c.Error(echo.ErrNotFound) + + // Assert + assert.Equal(t, http.StatusNotFound, rec.Code) + assert.Equal(t, errorJSON, rec.Body.String()) +} + +func TestHandleNotAllowedError(t *testing.T) { + // Arrange + var errorJSON = `{"code":"AU-1013","error":"errors.one.protocol.auth1.method_not_allowed"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = Handler + c := e.NewContext(httptest.NewRequest(http.MethodPost, "/", nil), rec) + + // Act + c.Error(echo.ErrMethodNotAllowed) + + // Assert + assert.Equal(t, http.StatusMethodNotAllowed, rec.Code) + assert.Equal(t, errorJSON, rec.Body.String()) +} + func TestHandleUnknownError(t *testing.T) { // Arrange var unkErrorJSON = `{"code":"AU-1000","error":"errors.one.protocol.auth1.unknown"} diff --git a/pkg/api/csrf_test.go b/pkg/api/csrf_test.go new file mode 100644 index 0000000..736f66c --- /dev/null +++ b/pkg/api/csrf_test.go @@ -0,0 +1,52 @@ +package api + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" +) + +func TestInvalidCSRFError(t *testing.T) { + // Arrange + var errorJSON = `{"code":"AU-1012","error":"errors.one.protocol.auth1.invalid_csrf_token","param":"x-xsrf-token"} +` + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = apierror.Handler + e.Use(CSRFWithConfig(CSRFConfig{ + TokenLookup: "header:X-XSRF-TOKEN", + CookieName: "_csrf", + })) + + // Act + e.ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/", nil)) + + // Assert + assert.Equal(t, http.StatusForbidden, rec.Code) + assert.Equal(t, errorJSON, rec.Body.String()) +} + +func TestCSRFVerification(t *testing.T) { + // Arrange + e, rec := echo.New(), httptest.NewRecorder() + e.HTTPErrorHandler = apierror.Handler + e.Use(CSRFWithConfig(CSRFConfig{ + TokenLookup: "header:X-XSRF-TOKEN", + CookieName: "_csrf", + })) + req := httptest.NewRequest(http.MethodPost, "/", nil) + req.Header.Add("x-xsrf-token", "0e8ff3c4-9f1c-4882-a105-086167fad6ff") + req.AddCookie(&http.Cookie{ + Name: "_csrf", + Value: "0e8ff3c4-9f1c-4882-a105-086167fad6ff", + }) + + // Act + e.ServeHTTP(rec, req) + + // Assert + assert.Equal(t, http.StatusNotFound, rec.Code) +} From 1252ff443a2ea067ba90747f8161e82086cada92 Mon Sep 17 00:00:00 2001 From: Behuamuh Date: Mon, 17 Feb 2020 16:17:35 +0300 Subject: [PATCH 045/251] Review fixes --- public/templates/email/change_password_2.html | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/public/templates/email/change_password_2.html b/public/templates/email/change_password_2.html index 336f723..dd18894 100644 --- a/public/templates/email/change_password_2.html +++ b/public/templates/email/change_password_2.html @@ -6,15 +6,15 @@ xmlns:v="urn:schemas-microsoft-com:vml" > - + @@ -103,10 +103,6 @@ .no-stack .col.num9 { width: 75% !important; } - - - - } From 8c116de26c7884820f5e071be9bb75423d7ff013 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 18 Feb 2020 10:35:13 +0300 Subject: [PATCH 046/251] update captcha error format --- pkg/api/apierror/errors.go | 1 + pkg/manager/oauth2.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go index c97e5b2..df0efe6 100644 --- a/pkg/api/apierror/errors.go +++ b/pkg/api/apierror/errors.go @@ -26,6 +26,7 @@ var ( InvalidCSRFToken = New(1012, "invalid_csrf_token", http.StatusForbidden).WithParam("x-xsrf-token") MethodNotAllowed = New(1013, "method_not_allowed", http.StatusMethodNotAllowed) NotFound = New(1014, "not_found", http.StatusNotFound) + CaptchaRequired = New(1015, "captcha_required", http.StatusForbidden) ) func New(code int, message string, status int) *APIError { diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 790af53..6857939 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -405,10 +405,10 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( if app.RequiresCaptcha { ok, err := CaptchaCompleted(ctx, m.session) if err != nil { - return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Error validate captcha")} + return "", errors.Wrap(err, "can't check captcha state") } if !ok { - return "", &models.GeneralError{Code: "captcha", Message: models.ErrorCaptchaRequired} + return "", apierror.CaptchaRequired } } From c9931d125c91eb5f85f8d723b2949092692698f4 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 18 Feb 2020 18:18:33 +0300 Subject: [PATCH 047/251] get app from challenge, not from session --- pkg/api/oauth2.go | 5 +++-- pkg/api/response_code.go | 6 +----- pkg/manager/oauth2.go | 8 ++++---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 4d7a483..756093e 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -201,7 +201,8 @@ func oauthSignUp(ctx echo.Context) error { func oauthCheckUsername(ctx echo.Context) error { var r struct { - Username string `json:"username"` + Challenge string `json:"challenge"` + Username string `json:"username"` } if err := ctx.Bind(&r); err != nil { @@ -210,7 +211,7 @@ func oauthCheckUsername(ctx echo.Context) error { m := ctx.Get("oauth_manager").(*manager.OauthManager) - ok, err := m.IsUsernameFree(ctx, r.Username) + ok, err := m.IsUsernameFree(ctx, r.Challenge, r.Username) if err != nil { return err } diff --git a/pkg/api/response_code.go b/pkg/api/response_code.go index 50fe2a4..36baeb5 100644 --- a/pkg/api/response_code.go +++ b/pkg/api/response_code.go @@ -1,11 +1,7 @@ package api +// Depricated const ( BadRequiredCodeField = `field:%s` BadRequiredCodeCommon = `invalid_argument` - MFARequiredCode = `mfa_required` - CaptchaRequiredCode = `captcha_required` - TemporaryLockedCode = `login_temporary_locked` - InvalidAuthTokenCode = `auth_token_invalid` - UnknownErrorCode = `unknown_error` ) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 6857939..d9c82e4 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -75,7 +75,7 @@ type OauthManagerInterface interface { SignUp(echo.Context, *models.Oauth2SignUpForm) (string, error) // IsUsernameFree checks if username is available for signup - IsUsernameFree(ctx echo.Context, username string) (bool, error) + IsUsernameFree(ctx echo.Context, challenge, username string) (bool, error) // CallBack verifies the result of oauth2 authorization. // @@ -352,12 +352,12 @@ func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2Introspec } func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, error) { - clientId, err := m.session.Get(ctx, clientIdSessionKey) + req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: form.Challenge, Context: ctx.Request().Context()}) if err != nil { - return false, errors.Wrap(err, "unable to get session") + return false, apierror.InvalidChallenge } - app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientId.(string))) + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(req.Payload.Client.ClientID)) if err != nil { return false, errors.Wrap(err, "unable to load application") } From eceada15deaf335972d366f6784786a9c69cf8ea Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 18 Feb 2020 20:13:54 +0300 Subject: [PATCH 048/251] get app from challenge, not from session --- pkg/manager/oauth2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index d9c82e4..4ddbceb 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -351,8 +351,8 @@ func (m *OauthManager) Introspect(ctx echo.Context, form *models.Oauth2Introspec return token, nil } -func (m *OauthManager) IsUsernameFree(ctx echo.Context, username string) (bool, error) { - req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: form.Challenge, Context: ctx.Request().Context()}) +func (m *OauthManager) IsUsernameFree(ctx echo.Context, challenge, username string) (bool, error) { + req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: challenge, Context: ctx.Request().Context()}) if err != nil { return false, apierror.InvalidChallenge } From 22de4c8d0b5c5983d6f80bfe73ff1b5b10137b5a Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 10:24:53 +0300 Subject: [PATCH 049/251] compose: web + api server --- .gitlab-ci.yml | 109 ------------------------------------- Makefile | 7 +++ docker-compose.yaml | 24 +++++--- etc/nginx/default.template | 32 +++++++++-- 4 files changed, 51 insertions(+), 121 deletions(-) delete mode 100644 .gitlab-ci.yml create mode 100644 Makefile diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 1628612..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,109 +0,0 @@ -variables: - P1_PROJECT: p1auth1 - -stages: - - build - - deploy - -build: - stage: build - before_script: - - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY - script: - - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID . - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID - - (if [ -f Dockerfile.nginx ]; then docker build -t $CI_REGISTRY_IMAGE:"$CI_COMMIT_REF_SLUG"-static.$CI_PIPELINE_ID -f Dockerfile.nginx . ; else echo "Project without static content"; fi); - - (if [ -f Dockerfile.nginx ]; then docker push $CI_REGISTRY_IMAGE:"$CI_COMMIT_REF_SLUG"-static.$CI_PIPELINE_ID ; else echo "Project without static content"; fi); - only: - - master - - develop - - -deploy_production: - stage: deploy - environment: - name: production - script: - - docker run - --rm - -v $PWD/.helm:/.helm - -e "K8S_API_URL=$K8S_API_URL" - -e "K8S_CI_TOKEN=$K8S_CI_TOKEN" - -e "P1_PROJECT=$P1_PROJECT" - -e "CI_PROJECT_PATH_SLUG=$CI_PROJECT_PATH_SLUG" - -e "CI_ENVIRONMENT_NAME=$CI_ENVIRONMENT_NAME" - -e "CI_REGISTRY=$CI_REGISTRY" - -e "CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE" - -e NGX_IMAGE=`if [ -f Dockerfile.nginx ]; then echo $CI_REGISTRY_IMAGE ; else echo nginx; fi` - -e "CI_PROJECT_NAMESPACE=$CI_PROJECT_NAMESPACE" - -e "CI_PROJECT_NAME=$CI_PROJECT_NAME" - -e "CI_COMMIT_REF_SLUG=$CI_COMMIT_REF_SLUG" - -e "CI_PIPELINE_ID=$CI_PIPELINE_ID" - -e "CI_DEPLOY_USER=$CI_DEPLOY_USER" - -e "CI_DEPLOY_PASSWORD=$CI_DEPLOY_PASSWORD" - p1hub/kubernetes-helm:2.11.0 - /bin/sh -c - 'kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=$K8S_API_URL && - kubectl config set-credentials ci --token=$K8S_CI_TOKEN && - kubectl config set-context ci --cluster=k8s --user=ci && - kubectl config use-context ci && - helm init --client-only && - helm upgrade --install $P1_PROJECT .helm - --set backend.image=$CI_REGISTRY_IMAGE - --set backend.imageTag="$CI_COMMIT_REF_SLUG".$CI_PIPELINE_ID - --set frontend.image=$NGX_IMAGE - --set frontend.imageTag="$CI_COMMIT_REF_SLUG"-static.$CI_PIPELINE_ID - --debug - --wait - --debug - --timeout 180 - ||(helm history --max 2 $P1_PROJECT | head -n 2 | tail -n 1 | awk "{print \$1}" | xargs helm rollback $P1_PROJECT && exit 1)' - only: - - master - when: on_success - -deploy_develop: - stage: deploy - environment: - name: production - script: - - docker run - --rm - -v $PWD/.helm:/.helm - -e "K8S_API_URL=$K8S_API_URL" - -e "K8S_CI_TOKEN=$K8S_CI_TOKEN" - -e "P1_PROJECT=$P1_PROJECT" - -e "CI_PROJECT_PATH_SLUG=$CI_PROJECT_PATH_SLUG" - -e "CI_ENVIRONMENT_NAME=$CI_ENVIRONMENT_NAME" - -e "CI_REGISTRY=$CI_REGISTRY" - -e "CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE" - -e NGX_IMAGE=`if [ -f Dockerfile.nginx ]; then echo $CI_REGISTRY_IMAGE ; else echo nginx; fi` - -e "CI_PROJECT_NAMESPACE=$CI_PROJECT_NAMESPACE" - -e "CI_PROJECT_NAME=$CI_PROJECT_NAME" - -e "CI_COMMIT_REF_SLUG=$CI_COMMIT_REF_SLUG" - -e "CI_PIPELINE_ID=$CI_PIPELINE_ID" - -e "CI_DEPLOY_USER=$CI_DEPLOY_USER" - -e "CI_DEPLOY_PASSWORD=$CI_DEPLOY_PASSWORD" - p1hub/kubernetes-helm:2.11.0 - /bin/sh -c - 'kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=$K8S_API_URL && - kubectl config set-credentials ci --token=$K8S_CI_TOKEN && - kubectl config set-context ci --cluster=k8s --user=ci && - kubectl config use-context ci && - helm init --client-only && - helm upgrade --install $P1_PROJECT-dev .helm - --namespace=dev - --set ingress.hostnamePrefix="dev-" - --set enableHydra=true - --set backend.image=$CI_REGISTRY_IMAGE - --set backend.imageTag="$CI_COMMIT_REF_SLUG".$CI_PIPELINE_ID - --set frontend.image=$NGX_IMAGE - --set frontend.imageTag="$CI_COMMIT_REF_SLUG"-static.$CI_PIPELINE_ID - --debug - --wait - --debug - --timeout 180 - ||(helm history --max 2 $P1_PROJECT | head -n 2 | tail -n 1 | awk "{print \$1}" | xargs helm rollback $P1_PROJECT && exit 1)' - only: - - develop - when: on_success diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..18bba9f --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: up +up: ## pull, builds and runs service and all deps + @docker-compose pull && docker-compose up --build + +.PHONY: upfast +upfast: ## pull, builds and runs service and all deps + @docker-compose up diff --git a/docker-compose.yaml b/docker-compose.yaml index 4726548..a9e9fc9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,8 +1,8 @@ version: "3.6" services: - web: - image: nginx + entry: + image: nginx:1.17.8 container_name: auth1-nginx networks: - subnet @@ -10,7 +10,7 @@ services: - hydra - auth1 ports: - - "80:80" + - "7001:80" - "6060:6060" environment: - NGINX_HOST=localhost @@ -19,11 +19,18 @@ services: - AUTHONE_SERVER=http://auth1:8080 - AUTHONE_DEBUG=http://auth1:6060 - HYDRA_SERVER=http://hydra:4444 + - WEB_SERVER=http://auth1-web:80 - DOLLAR=$$ volumes: - ./etc/nginx/default.template:/etc/nginx/conf.d/default.template command: bin/bash -c " envsubst < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" + web: + image: p1hub/store-auth-web:master-35 + container_name: auth1-web + networks: + - subnet + hydra-migrate: image: oryd/hydra:v1.0.0-rc.9_oryOS.10 container_name: hydra-migrate @@ -48,11 +55,12 @@ services: - subnet environment: - DSN=postgres://hydra:secret@auth1-postgres/hydra?sslmode=disable - - URLS_SELF_ISSUER=http://localhost - - URLS_SELF_PUBLIC=http://localhost - - URLS_CONSENT=http://localhost/oauth2/consent - - URLS_LOGIN=http://localhost/oauth2/login - - URLS_POST_LOGOUT_REDIRECT=http://localhost/oauth2/logout + - URLS_SELF_ISSUER=http://localhost:7001 + - URLS_SELF_PUBLIC=http://localhost:7001 + - URLS_CONSENT=http://localhost:7001/oauth2/consent + - URLS_LOGIN=http://localhost:7001/sign-in + - URLS_ERROR=http://localhost:7001/error + - URLS_POST_LOGOUT_REDIRECT=http://localhost:7001/oauth2/logout - LOG_LEVEL=debug - OAUTH2_HASHERS_BCRYPT_COST=8 - SECRETS_SYSTEM=newYouReallyNeedToChangeThis youReallyNeedToChangeThis diff --git a/etc/nginx/default.template b/etc/nginx/default.template index 9d34161..61c6fd5 100644 --- a/etc/nginx/default.template +++ b/etc/nginx/default.template @@ -2,11 +2,23 @@ server { listen ${NGINX_PORT}; server_name ${NGINX_HOST}; - location ~* ^/oauth2/auth/sessions/login/revoke(.*)$ { + location /oauth2/auth { proxy_pass ${HYDRA_SERVER}; } - location ~* ^/oauth2/(auth|token|revoke)(.*)$ { + location /oauth2/token { + proxy_pass ${HYDRA_SERVER}; + } + + location /oauth2/revoke { + proxy_pass ${HYDRA_SERVER}; + } + + location /oauth2/fallbacks/concent { + proxy_pass ${HYDRA_SERVER}; + } + + location /oauth2/fallbacks/error { proxy_pass ${HYDRA_SERVER}; } @@ -14,16 +26,28 @@ server { proxy_pass ${HYDRA_SERVER}; } + location /.well-known/openid-configuration { + proxy_pass ${HYDRA_SERVER}; + } + location /oauth2/userinfo { rewrite ^/oauth2/userinfo(.*)$ /userinfo$1 break; proxy_pass ${HYDRA_SERVER}; } - location / { + location /oauth2 { + proxy_pass ${AUTHONE_SERVER}; + } + + location /api { proxy_pass ${AUTHONE_SERVER}; - proxy_set_header Host localhost; + } + + location / { + proxy_pass ${WEB_SERVER}; } } + server { listen ${DEBUG_PORT}; server_name ${NGINX_HOST}; From a3b6039cac01624c91bd1973409b7e4ab6666854 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 10:42:43 +0300 Subject: [PATCH 050/251] update ingress --- .helm/templates/ingress.yaml | 16 ++++++++++++---- etc/nginx/default.template | 8 -------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.helm/templates/ingress.yaml b/.helm/templates/ingress.yaml index 841e46f..37ecb69 100644 --- a/.helm/templates/ingress.yaml +++ b/.helm/templates/ingress.yaml @@ -26,10 +26,6 @@ spec: - host: {{printf "%s%s" .Values.ingress.hostnamePrefix .Values.ingress.hostname }} http: paths: - - path: {{ .Values.ingress.path }} - backend: - serviceName: {{ .Release.Name }} - servicePort: {{ $endpoint.service.port }} - path: /userinfo backend: serviceName: {{ $hydraSvc }} @@ -58,3 +54,15 @@ spec: backend: serviceName: {{ $hydraSvc }} servicePort: 4444 + - path: /oauth2 + backend: + serviceName: {{ .Release.Name }} + servicePort: {{ $endpoint.service.port }} + - path: /api + backend: + serviceName: {{ .Release.Name }} + servicePort: {{ $endpoint.service.port }} + - path: / + backend: + serviceName: store-auth-web + servicePort: 80 diff --git a/etc/nginx/default.template b/etc/nginx/default.template index 61c6fd5..afbdf7d 100644 --- a/etc/nginx/default.template +++ b/etc/nginx/default.template @@ -14,14 +14,6 @@ server { proxy_pass ${HYDRA_SERVER}; } - location /oauth2/fallbacks/concent { - proxy_pass ${HYDRA_SERVER}; - } - - location /oauth2/fallbacks/error { - proxy_pass ${HYDRA_SERVER}; - } - location /.well-known/jwks.json { proxy_pass ${HYDRA_SERVER}; } From 5acb9275d2c513793fc12924205691453c6b450f Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 12:52:37 +0300 Subject: [PATCH 051/251] compose: switch to web latest master version --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index a9e9fc9..ff0e6d2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -26,7 +26,7 @@ services: command: bin/bash -c " envsubst < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" web: - image: p1hub/store-auth-web:master-35 + image: p1hub/store-auth-web:master container_name: auth1-web networks: - subnet From 25a26126378618a23d3cd77da3bbbd08f7b92254 Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 19 Feb 2020 14:17:18 +0300 Subject: [PATCH 052/251] update helm chart --- .helm/Chart.yaml | 2 +- .helm/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.helm/Chart.yaml b/.helm/Chart.yaml index 5b60011..8fb9818 100644 --- a/.helm/Chart.yaml +++ b/.helm/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 appVersion: "1.0" description: A Helm chart for Protocol.One Auth1 service -name: p1auth1 +name: qilinauth version: 0.0.1 diff --git a/.helm/values.yaml b/.helm/values.yaml index af7ae8f..49b08a1 100644 --- a/.helm/values.yaml +++ b/.helm/values.yaml @@ -8,7 +8,7 @@ enableCertIssuer: true enableHydraDebug: false ingress: - hostname: auth1.tst.protocol.one + hostname: id.tst.qilin.super.com hostnamePrefix: path: / From a4cb736f9d8437d2b948b163370f1130473798d0 Mon Sep 17 00:00:00 2001 From: Valentin Vesvalo Date: Wed, 19 Feb 2020 14:29:38 +0300 Subject: [PATCH 053/251] update ci/cd --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index bd5cc02..6db14b9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,8 @@ @Library('p1pipeline')_ p1pipeline( - "p1auth1", //helm release name - "p1auth1", // docker hub registry + "qilinauth", //helm release name + "qilinauth", // docker hub registry "develop", // development branch for test releases "dev", // kubernetes namespace for test releases "dev-" // domain name prefix in kubernetes for test releases From 506f1633f0c31fa0b38d467915d36b2162ea5181 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 16:35:28 +0300 Subject: [PATCH 054/251] fix signup --- pkg/manager/oauth2.go | 14 +--- pkg/manager/oauth2_test.go | 133 +++++++++++++++++++------------------ 2 files changed, 72 insertions(+), 75 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 4ddbceb..e555bb6 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -392,12 +392,12 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return "", errors.Wrap(err, "error saving session") } - clientId, err := m.session.Get(ctx, clientIdSessionKey) + req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: form.Challenge, Context: ctx.Request().Context()}) if err != nil { - return "", errors.Wrap(err, "unable to get session") + return "", apierror.InvalidChallenge } - app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientId.(string))) + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(req.Payload.Client.ClientID)) if err != nil { return "", errors.Wrap(err, "unable to load application") } @@ -435,14 +435,6 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return err }) - req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Context: ctx.Request().Context(), Challenge: form.Challenge}) - if err != nil { - return "", apierror.InvalidChallenge - } - if req.Payload.Client.ClientID != clientId.(string) { - return "", errors.New("client ID is incorrect") - } - ipc := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) if ipc == nil { return "", errors.New("unable to get identity provider") diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 5221318..1985644 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -1,7 +1,6 @@ package manager import ( - "fmt" "testing" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" @@ -801,55 +800,60 @@ func TestSignUpReturnErrorWithUnableToSetRememberToSession(t *testing.T) { // assert.Equal(t, models.ErrorUnknownError, err.Message) } -func TestSignUpReturnErrorWithUnableToGetClientFromSession(t *testing.T) { - s := &mocks.SessionService{} - app := &mocks.ApplicationServiceInterface{} - r := &mocks.InternalRegistry{} - - s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) - s.On("Get", mock.Anything, clientIdSessionKey).Return(nil, errors.New("")) - r.On("ApplicationService").Return(app) - - m := &OauthManager{ - r: r, - session: s, - } - _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) - assert.NotNil(t, err) - // assert.Equal(t, "common", err.Code) - // assert.Equal(t, models.ErrorUnknownError, err.Message) -} - -func TestSignUpReturnErrorWithUnableToGetApplication(t *testing.T) { - s := &mocks.SessionService{} - app := &mocks.ApplicationServiceInterface{} - r := &mocks.InternalRegistry{} - - s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) - s.On("Get", mock.Anything, clientIdSessionKey).Return(bson.NewObjectId().Hex(), nil) - app.On("Get", mock.Anything).Return(nil, errors.New("")) - r.On("ApplicationService").Return(app) - - m := &OauthManager{ - r: r, - session: s, - } - _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) - assert.NotNil(t, err) - // assert.Equal(t, "client_id", err.Code) - // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) -} +// GET APP FROM HYDRA NOT SESSION +// func TestSignUpReturnErrorWithUnableToGetClientFromSession(t *testing.T) { +// s := &mocks.SessionService{} +// app := &mocks.ApplicationServiceInterface{} +// r := &mocks.InternalRegistry{} + +// s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) +// s.On("Get", mock.Anything, clientIdSessionKey).Return(nil, errors.New("")) +// r.On("ApplicationService").Return(app) + +// m := &OauthManager{ +// r: r, +// session: s, +// } +// _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) +// assert.NotNil(t, err) +// // assert.Equal(t, "common", err.Code) +// // assert.Equal(t, models.ErrorUnknownError, err.Message) +// } + +// GET APP FROM HYDRA NOT SESSION +// func TestSignUpReturnErrorWithUnableToGetApplication(t *testing.T) { +// s := &mocks.SessionService{} +// app := &mocks.ApplicationServiceInterface{} +// r := &mocks.InternalRegistry{} + +// s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) +// s.On("Get", mock.Anything, clientIdSessionKey).Return(bson.NewObjectId().Hex(), nil) +// app.On("Get", mock.Anything).Return(nil, errors.New("")) +// r.On("ApplicationService").Return(app) + +// m := &OauthManager{ +// r: r, +// session: s, +// } +// _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true}) +// assert.NotNil(t, err) +// // assert.Equal(t, "client_id", err.Code) +// // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) +// } func TestSignUpReturnErrorWithInvalidPassword(t *testing.T) { s := &mocks.SessionService{} app := &mocks.ApplicationServiceInterface{} r := &mocks.InternalRegistry{} + h := &mocks.HydraAdminApi{} passSettings := &models.PasswordSettings{Min: 2, Max: 8, RequireSpecial: false, RequireUpper: false, RequireNumber: false} s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) s.On("Get", mock.Anything, clientIdSessionKey).Return(bson.NewObjectId().Hex(), nil) app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) r.On("ApplicationService").Return(app) + h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.Client{ClientID: bson.NewObjectId().Hex()}}}, nil) + r.On("HydraAdminApi").Return(h) m := &OauthManager{ r: r, @@ -885,31 +889,32 @@ func TestSignUpReturnErrorWithUnableToGetLoginChallenge(t *testing.T) { // assert.Equal(t, models.ErrorLoginChallenge, err.Message) } -func TestSignUpReturnErrorWithDifferentClientId(t *testing.T) { - s := &mocks.SessionService{} - app := &mocks.ApplicationServiceInterface{} - h := &mocks.HydraAdminApi{} - r := &mocks.InternalRegistry{} - - passSettings := &models.PasswordSettings{Min: 2, Max: 8, RequireSpecial: false, RequireUpper: false, RequireNumber: false} - s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) - s.On("Get", mock.Anything, clientIdSessionKey).Return(bson.NewObjectId().Hex(), nil) - app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) - h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.Client{ClientID: bson.NewObjectId().Hex()}}}, nil) - r.On("ApplicationService").Return(app) - r.On("HydraAdminApi").Return(h) - - m := &OauthManager{ - r: r, - session: s, - } - _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) - - fmt.Println(err) - assert.NotNil(t, err) - // assert.Equal(t, "client_id", err.Code) - // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) -} +// NOT POSSIBLE ANY MORE +// func TestSignUpReturnErrorWithDifferentClientId(t *testing.T) { +// s := &mocks.SessionService{} +// app := &mocks.ApplicationServiceInterface{} +// h := &mocks.HydraAdminApi{} +// r := &mocks.InternalRegistry{} + +// passSettings := &models.PasswordSettings{Min: 2, Max: 8, RequireSpecial: false, RequireUpper: false, RequireNumber: false} +// s.On("Set", mock.Anything, loginRememberKey, true).Return(nil) +// s.On("Get", mock.Anything, clientIdSessionKey).Return(bson.NewObjectId().Hex(), nil) +// app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) +// h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.Client{ClientID: bson.NewObjectId().Hex()}}}, nil) +// r.On("ApplicationService").Return(app) +// r.On("HydraAdminApi").Return(h) + +// m := &OauthManager{ +// r: r, +// session: s, +// } +// _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) + +// fmt.Println(err) +// assert.NotNil(t, err) +// // assert.Equal(t, "client_id", err.Code) +// // assert.Equal(t, models.ErrorClientIdIncorrect, err.Message) +// } func TestSignUpReturnErrorWithUnavailableIdentityProvider(t *testing.T) { s := &mocks.SessionService{} From f2251559880dcb4ca8c5166cf09da096d4ccdcb4 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 17:02:19 +0300 Subject: [PATCH 055/251] update authorize api and callback --- etc/nginx/default.template | 2 + pkg/api/login.go | 148 +++++++++++----------- pkg/manager/login.go | 5 +- pkg/service/app_identity_provider.go | 17 +-- pkg/service/app_identity_provider_test.go | 7 +- 5 files changed, 92 insertions(+), 87 deletions(-) diff --git a/etc/nginx/default.template b/etc/nginx/default.template index afbdf7d..e07d57d 100644 --- a/etc/nginx/default.template +++ b/etc/nginx/default.template @@ -2,6 +2,8 @@ server { listen ${NGINX_PORT}; server_name ${NGINX_HOST}; + proxy_set_header Host ${DOLLAR}http_host; + location /oauth2/auth { proxy_pass ${HYDRA_SERVER}; } diff --git a/pkg/api/login.go b/pkg/api/login.go index d1b5827..ce495f8 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -2,20 +2,20 @@ package api import ( "fmt" + "net/http" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" - jwtverifier "github.com/ProtocolONE/authone-jwt-verifier-golang" "github.com/labstack/echo/v4" - "net/http" - "strings" ) func InitLogin(cfg *Server) error { - cfg.Echo.GET("/login/form", loginPage) + // cfg.Echo.GET("/login/form", loginPage) - g := cfg.Echo.Group("/authorize", func(next echo.HandlerFunc) echo.HandlerFunc { + g := cfg.Echo.Group("/api/authorize", func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { db := c.Get("database").(database.MgoSession) c.Set("login_manager", manager.NewLoginManager(db, cfg.Registry)) @@ -36,22 +36,19 @@ func authorize(ctx echo.Context) error { m := ctx.Get("login_manager").(*manager.LoginManager) if err := ctx.Bind(form); err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) + return apierror.InvalidRequest(err) } if err := ctx.Validate(form); err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusBadRequest, models.ErrorRequiredField) + return apierror.InvalidParameters(err) } - str, err := m.Authorize(ctx, form) + url, err := m.Authorize(ctx, form) if err != nil { - ctx.Error(err.Err) - return ctx.HTML(http.StatusBadRequest, err.Message) + return err } - return ctx.Redirect(http.StatusMovedPermanently, str) + return ctx.Redirect(http.StatusMovedPermanently, url) } func authorizeResult(ctx echo.Context) error { @@ -59,36 +56,39 @@ func authorizeResult(ctx echo.Context) error { m := ctx.Get("login_manager").(*manager.LoginManager) if err := ctx.Bind(form); err != nil { - e := &models.GeneralError{ - Code: BadRequiredCodeCommon, - Message: models.ErrorInvalidRequestParameters, - } - ctx.Error(err) - return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ - "Result": &manager.SocialAccountError, - "Payload": map[string]interface{}{"code": e.Code, "message": e.Message}, - }) + return apierror.InvalidRequest(err) + // e := &models.GeneralError{ + // Code: BadRequiredCodeCommon, + // Message: models.ErrorInvalidRequestParameters, + // } + // ctx.Error(err) + // return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ + // "Result": &manager.SocialAccountError, + // "Payload": map[string]interface{}{"code": e.Code, "message": e.Message}, + // }) } if err := ctx.Validate(form); err != nil { - e := &models.GeneralError{ - Code: fmt.Sprintf(BadRequiredCodeField, helper.GetSingleError(err).Field()), - Message: models.ErrorRequiredField, - } - ctx.Error(err) - return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ - "Result": &manager.SocialAccountError, - "Payload": map[string]interface{}{"code": e.Code, "message": e.Message}, - }) + return apierror.InvalidParameters(err) + // e := &models.GeneralError{ + // Code: fmt.Sprintf(BadRequiredCodeField, helper.GetSingleError(err).Field()), + // Message: models.ErrorRequiredField, + // } + // ctx.Error(err) + // return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ + // "Result": &manager.SocialAccountError, + // "Payload": map[string]interface{}{"code": e.Code, "message": e.Message}, + // }) } t, err := m.AuthorizeResult(ctx, form) if err != nil { - ctx.Error(err.Err) - return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ - "Result": &manager.SocialAccountError, - "Payload": map[string]interface{}{"code": err.Code, "message": err.Message}, - }) + return err + // ctx.Error(err.Err) + // return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ + // "Result": &manager.SocialAccountError, + // "Payload": map[string]interface{}{"code": err.Code, "message": err.Message}, + // }) } return ctx.Render(http.StatusOK, "social_auth_result.html", map[string]interface{}{ @@ -128,41 +128,41 @@ func authorizeLink(ctx echo.Context) error { return ctx.JSON(http.StatusOK, map[string]string{"url": url}) } -func loginPage(ctx echo.Context) (err error) { - form := new(models.LoginPageForm) - - if err := ctx.Bind(form); err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) - } - - url, err := createAuthUrl(ctx, form) - if err != nil { - ctx.Error(err) - return ctx.HTML(http.StatusInternalServerError, "Unable to authorize, please come back later") - } - - return ctx.Redirect(http.StatusMovedPermanently, url) -} - -func createAuthUrl(ctx echo.Context, form *models.LoginPageForm) (string, error) { - scopes := []string{"openid"} - if form.Scopes != "" { - scopes = strings.Split(form.Scopes, " ") - } - - if form.RedirectUri == "" { - form.RedirectUri = fmt.Sprintf("%s://%s/oauth2/callback", ctx.Scheme(), ctx.Request().Host) - } - - settings := jwtverifier.Config{ - ClientID: form.ClientID, - ClientSecret: "", - Scopes: scopes, - RedirectURL: form.RedirectUri, - Issuer: fmt.Sprintf("%s://%s", ctx.Scheme(), ctx.Request().Host), - } - jwtv := jwtverifier.NewJwtVerifier(settings) - - return jwtv.CreateAuthUrl(form.State), nil -} +// func loginPage(ctx echo.Context) (err error) { +// form := new(models.LoginPageForm) + +// if err := ctx.Bind(form); err != nil { +// ctx.Error(err) +// return ctx.HTML(http.StatusBadRequest, models.ErrorInvalidRequestParameters) +// } + +// url, err := createAuthUrl(ctx, form) +// if err != nil { +// ctx.Error(err) +// return ctx.HTML(http.StatusInternalServerError, "Unable to authorize, please come back later") +// } + +// return ctx.Redirect(http.StatusMovedPermanently, url) +// } + +// func createAuthUrl(ctx echo.Context, form *models.LoginPageForm) (string, error) { +// scopes := []string{"openid"} +// if form.Scopes != "" { +// scopes = strings.Split(form.Scopes, " ") +// } + +// if form.RedirectUri == "" { +// form.RedirectUri = fmt.Sprintf("%s://%s/oauth2/callback", ctx.Scheme(), ctx.Request().Host) +// } + +// settings := jwtverifier.Config{ +// ClientID: form.ClientID, +// ClientSecret: "", +// Scopes: scopes, +// RedirectURL: form.RedirectUri, +// Issuer: fmt.Sprintf("%s://%s", ctx.Scheme(), ctx.Request().Host), +// } +// jwtv := jwtverifier.NewJwtVerifier(settings) + +// return jwtv.CreateAuthUrl(form.State), nil +// } diff --git a/pkg/manager/login.go b/pkg/manager/login.go index b16a884..77dff28 100644 --- a/pkg/manager/login.go +++ b/pkg/manager/login.go @@ -4,6 +4,9 @@ import ( "encoding/base64" "encoding/json" "fmt" + "net/http" + "time" + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" @@ -14,8 +17,6 @@ import ( "github.com/ory/hydra/sdk/go/hydra/client/admin" models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" - "net/http" - "time" ) var ( diff --git a/pkg/service/app_identity_provider.go b/pkg/service/app_identity_provider.go index 5b67f13..91abb7f 100644 --- a/pkg/service/app_identity_provider.go +++ b/pkg/service/app_identity_provider.go @@ -6,6 +6,13 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "regexp" + "strings" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/globalsign/mgo/bson" "github.com/pkg/errors" @@ -14,12 +21,6 @@ import ( "golang.org/x/oauth2/google" "golang.org/x/oauth2/twitch" "golang.org/x/oauth2/vk" - "io/ioutil" - "net/http" - "net/url" - "reflect" - "regexp" - "strings" ) // AppIdentityProviderServiceInterface describes of methods for the AppIdentityProviderService. @@ -209,7 +210,7 @@ func (s *AppIdentityProviderService) GetAuthUrl(domain string, ip *models.AppIde v := url.Values{ "response_type": {"code"}, "client_id": {ip.ClientID}, - "redirect_uri": {fmt.Sprintf("%s/authorize/result", domain)}, + "redirect_uri": {fmt.Sprintf("%s/api/authorize/result", domain)}, } if len(ip.ClientScopes) > 0 { v.Set("scope", strings.Join(ip.ClientScopes, " ")) @@ -229,7 +230,7 @@ func (s *AppIdentityProviderService) GetAuthUrl(domain string, ip *models.AppIde } func (s *AppIdentityProviderService) GetSocialProfile(ctx context.Context, domain string, code string, ip *models.AppIdentityProvider) (*models.UserIdentitySocial, error) { - rUrl := fmt.Sprintf("%s/authorize/result", domain) + rUrl := fmt.Sprintf("%s/api/authorize/result", domain) conf := &oauth2.Config{ ClientID: ip.ClientID, ClientSecret: ip.ClientSecret, diff --git a/pkg/service/app_identity_provider_test.go b/pkg/service/app_identity_provider_test.go index 4f18b43..55a673b 100644 --- a/pkg/service/app_identity_provider_test.go +++ b/pkg/service/app_identity_provider_test.go @@ -2,11 +2,12 @@ package service import ( "fmt" + "regexp" + "testing" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/globalsign/mgo/bson" "github.com/stretchr/testify/assert" - "regexp" - "testing" ) func TestIdentityProviderGetReturnProvider(t *testing.T) { @@ -168,6 +169,6 @@ func TestIdentityProvidersGetAuthUrl(t *testing.T) { ipc := &models.AppIdentityProvider{EndpointAuthURL: "http://localhost/", ClientID: "1"} url, _ := ip.GetAuthUrl("http://localhost", ipc, "") - expected := "http://localhost/?client_id=1&redirect_uri=http%3A%2F%2Flocalhost%2Fauthorize%2Fresult&response_type=code&state=IiI%3D" + expected := "http://localhost/?client_id=1&redirect_uri=http%3A%2F%2Flocalhost%2Fapi%2Fauthorize%2Fresult&response_type=code&state=IiI%3D" assert.Equal(t, expected, url, "Invalid social auth url") } From 2e04c38b9541ede67f39dbd82b5f05aa0b486f93 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 19 Feb 2020 17:27:11 +0300 Subject: [PATCH 056/251] don't expose registered emails on sign in --- pkg/manager/oauth2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index e555bb6..19a6876 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -192,7 +192,7 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm userIdentity, err = m.userIdentityService.Get(app, ipc, form.Email) if err != nil { - return "", apierror.EmailNotFound + return "", apierror.InvalidCredentials } encryptor := models.NewBcryptEncryptor(&models.CryptConfig{Cost: app.PasswordSettings.BcryptCost}) From 43cec9bbbd3545d8d7a0b1fed480a4e7fefabfcf Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Fri, 21 Feb 2020 11:14:57 +0300 Subject: [PATCH 057/251] api for get captcha client keys --- pkg/api/apierror/errors.go | 1 + pkg/api/captcha.go | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go index df0efe6..53c8a6f 100644 --- a/pkg/api/apierror/errors.go +++ b/pkg/api/apierror/errors.go @@ -27,6 +27,7 @@ var ( MethodNotAllowed = New(1013, "method_not_allowed", http.StatusMethodNotAllowed) NotFound = New(1014, "not_found", http.StatusNotFound) CaptchaRequired = New(1015, "captcha_required", http.StatusForbidden) + UnknownCaptchaType = New(1016, "unknown_captcha_type", http.StatusBadRequest) ) func New(code int, message string, status int) *APIError { diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index 6d47981..056fcff 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -15,8 +15,9 @@ func InitCaptcha(cfg *Server) error { recaptcha: cfg.Recaptcha, session: service.NewSessionService(cfg.SessionConfig.Name), } - cfg.Echo.Group("/api/captcha"). - POST("/re3", c.verify) + g := cfg.Echo.Group("/api/captcha") + g.POST("/re3", c.verify) + g.GET("/key", c.key) return nil } @@ -49,3 +50,16 @@ func (ctl *Captcha) verify(ctx echo.Context) error { "success": result, }) } + +func (ctl *Captcha) key(ctx echo.Context) error { + tp := ctx.QueryParam("type") + + switch tp { + case "re3": + return ctx.JSON(http.StatusOK, map[string]interface{}{ + "key": ctl.recaptcha.Key(), + }) + default: + return apierror.UnknownCaptchaType + } +} From 3220b3af7329e03afea174f52da3ae0e210d58c6 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Fri, 21 Feb 2020 12:07:06 +0300 Subject: [PATCH 058/251] allow pass captcha token in signup form --- pkg/api/captcha.go | 7 ++-- pkg/api/oauth2.go | 2 +- pkg/api/server.go | 5 +-- pkg/{service => captcha}/recaptcha.go | 2 +- pkg/captcha/session.go | 27 +++++++++++++++ pkg/manager/oauth2.go | 50 ++++++++++++++++----------- pkg/manager/oauth2_test.go | 2 +- pkg/models/oauth2.go | 3 ++ 8 files changed, 68 insertions(+), 30 deletions(-) rename pkg/{service => captcha}/recaptcha.go (99%) create mode 100644 pkg/captcha/session.go diff --git a/pkg/api/captcha.go b/pkg/api/captcha.go index 056fcff..77069d2 100644 --- a/pkg/api/captcha.go +++ b/pkg/api/captcha.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/ProtocolONE/auth1.protocol.one/pkg/captcha" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/labstack/echo/v4" "github.com/pkg/errors" @@ -22,10 +23,8 @@ func InitCaptcha(cfg *Server) error { return nil } -var captchaKey = "captcha" - type Captcha struct { - recaptcha *service.Recaptcha + recaptcha *captcha.Recaptcha session service.SessionService } @@ -44,7 +43,7 @@ func (ctl *Captcha) verify(ctx echo.Context) error { return errors.Wrap(err, "unable to verify captcha") } - ctl.session.Set(ctx, captchaKey, result) + captcha.StoreCompletedStatus(ctx, ctl.session, result) return ctx.JSON(http.StatusOK, map[string]interface{}{ "success": result, diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 756093e..74178a4 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -15,7 +15,7 @@ func InitOauth2(cfg *Server) error { g := cfg.Echo.Group("/oauth2", func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { db := c.Get("database").(database.MgoSession) - c.Set("oauth_manager", manager.NewOauthManager(db, cfg.Registry, cfg.SessionConfig, cfg.HydraConfig, cfg.ServerConfig)) + c.Set("oauth_manager", manager.NewOauthManager(db, cfg.Registry, cfg.SessionConfig, cfg.HydraConfig, cfg.ServerConfig, cfg.Recaptcha)) return next(c) } diff --git a/pkg/api/server.go b/pkg/api/server.go index 41edd2d..a972962 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -14,6 +14,7 @@ import ( "time" "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/ProtocolONE/auth1.protocol.one/pkg/captcha" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -84,7 +85,7 @@ type Server struct { Registry service.InternalRegistry // Recaptcha is recaptcha integration - Recaptcha *service.Recaptcha + Recaptcha *captcha.Recaptcha } // Template is used to display HTML pages. @@ -108,7 +109,7 @@ func NewServer(c *ServerConfig) (*Server, error) { SessionConfig: c.SessionConfig, HydraConfig: c.HydraConfig, Registry: service.NewRegistryBase(registryConfig), - Recaptcha: service.NewRecaptcha(c.Recaptcha.Key, c.Recaptcha.Secret, c.Recaptcha.Hostname), + Recaptcha: captcha.NewRecaptcha(c.Recaptcha.Key, c.Recaptcha.Secret, c.Recaptcha.Hostname), } t := &Template{ diff --git a/pkg/service/recaptcha.go b/pkg/captcha/recaptcha.go similarity index 99% rename from pkg/service/recaptcha.go rename to pkg/captcha/recaptcha.go index 8b67fad..a2e629d 100644 --- a/pkg/service/recaptcha.go +++ b/pkg/captcha/recaptcha.go @@ -1,4 +1,4 @@ -package service +package captcha import ( "context" diff --git a/pkg/captcha/session.go b/pkg/captcha/session.go new file mode 100644 index 0000000..561e60c --- /dev/null +++ b/pkg/captcha/session.go @@ -0,0 +1,27 @@ +package captcha + +import ( + "github.com/ProtocolONE/auth1.protocol.one/pkg/service" + "github.com/labstack/echo/v4" +) + +const captchaKey = "captcha" + +// IsCompleted checks if session has flag that captcha was verified +func IsCompleted(ctx echo.Context, s service.SessionService) (bool, error) { + v, err := s.Get(ctx, captchaKey) + if err != nil { + return false, err + } + if v != nil { + if done, ok := v.(bool); ok { + return done, nil + } + } + return false, nil +} + +// StoreCompletedStatus attachs captcha verification status to client session +func StoreCompletedStatus(ctx echo.Context, s service.SessionService, value bool) error { + return s.Set(ctx, captchaKey, value) +} diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 19a6876..4b3416c 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -1,8 +1,12 @@ package manager import ( + "context" "fmt" + "time" + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/ProtocolONE/auth1.protocol.one/pkg/captcha" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -16,7 +20,6 @@ import ( models2 "github.com/ory/hydra/sdk/go/hydra/models" "github.com/pkg/errors" "gopkg.in/tomb.v2" - "time" ) const ( @@ -102,10 +105,17 @@ type OauthManager struct { r service.InternalRegistry session service.SessionService ApiCfg *config.Server + recaptcha *captcha.Recaptcha } // NewOauthManager return new oauth manager. -func NewOauthManager(db database.MgoSession, r service.InternalRegistry, s *config.Session, h *config.Hydra, apiCfg *config.Server) OauthManagerInterface { +func NewOauthManager( + db database.MgoSession, + r service.InternalRegistry, + s *config.Session, + h *config.Hydra, + apiCfg *config.Server, + recaptcha *captcha.Recaptcha) OauthManagerInterface { m := &OauthManager{ ApiCfg: apiCfg, hydraConfig: h, @@ -115,6 +125,7 @@ func NewOauthManager(db database.MgoSession, r service.InternalRegistry, s *conf authLogService: service.NewAuthLogService(db), identityProviderService: service.NewAppIdentityProviderService(), session: service.NewSessionService(s.Name), + recaptcha: recaptcha, } return m @@ -374,19 +385,6 @@ func (m *OauthManager) IsUsernameFree(ctx echo.Context, challenge, username stri return ok, nil } -func CaptchaCompleted(ctx echo.Context, s service.SessionService) (bool, error) { - v, err := s.Get(ctx, "captcha") - if err != nil { - return false, err - } - if v != nil { - if done, ok := v.(bool); ok { - return done, nil - } - } - return false, nil -} - func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) (string, error) { if err := m.session.Set(ctx, loginRememberKey, form.Remember); err != nil { return "", errors.Wrap(err, "error saving session") @@ -403,12 +401,22 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( } if app.RequiresCaptcha { - ok, err := CaptchaCompleted(ctx, m.session) - if err != nil { - return "", errors.Wrap(err, "can't check captcha state") - } - if !ok { - return "", apierror.CaptchaRequired + if form.Captcha != "" { + ok, err := m.recaptcha.Verify(context.TODO(), form.Captcha, "", "") // TODO ip, action + if err != nil { + return "", errors.Wrap(err, "can't verify captcha token") + } + if !ok { + return "", apierror.CaptchaRequired + } + } else { + ok, err := captcha.IsCompleted(ctx, m.session) + if err != nil { + return "", errors.Wrap(err, "can't check captcha state") + } + if !ok { + return "", apierror.CaptchaRequired + } } } diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 1985644..5375e5a 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -18,7 +18,7 @@ import ( func TestOauthManager(t *testing.T) { s := &mocks.MgoSession{} s.On("DB", mock.Anything).Return(&mgo.Database{}) - m := NewOauthManager(s, &mocks.InternalRegistry{}, &config.Session{Name: ""}, &config.Hydra{}, nil) + m := NewOauthManager(s, &mocks.InternalRegistry{}, &config.Session{Name: ""}, &config.Hydra{}, nil, nil) assert.Implements(t, (*OauthManagerInterface)(nil), m) } diff --git a/pkg/models/oauth2.go b/pkg/models/oauth2.go index 4c61f78..1d8a005 100644 --- a/pkg/models/oauth2.go +++ b/pkg/models/oauth2.go @@ -167,6 +167,9 @@ type Oauth2SignUpForm struct { // Remember is the option for the save user session in the cookie. Remember bool `query:"remember" form:"remember"` + + // Captcha is optional captcha token for real user validation + Captcha string `query:"captcha" form:"captcha"` } func (a *Oauth2SignUpForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { From b672fa7b3ef2093f98dac08db675092fb4d2ee6f Mon Sep 17 00:00:00 2001 From: Serge Date: Fri, 21 Feb 2020 17:37:10 +0500 Subject: [PATCH 059/251] feat: password change without session drops --- Makefile | 9 +- pkg/api/apierror/errors.go | 1 + pkg/api/manage.go | 106 +++++++++++++++++- pkg/manager/change_password.go | 49 +++++++- public/templates/email/change_password_2.html | 12 +- 5 files changed, 163 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 18bba9f..f0c2e91 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,12 @@ +.PHONY: down +down: ## stops containers + @docker-compose down + + .PHONY: up up: ## pull, builds and runs service and all deps - @docker-compose pull && docker-compose up --build + @docker-compose pull && docker-compose up --build -d .PHONY: upfast upfast: ## pull, builds and runs service and all deps - @docker-compose up + @docker-compose up -d diff --git a/pkg/api/apierror/errors.go b/pkg/api/apierror/errors.go index 53c8a6f..167060a 100644 --- a/pkg/api/apierror/errors.go +++ b/pkg/api/apierror/errors.go @@ -28,6 +28,7 @@ var ( NotFound = New(1014, "not_found", http.StatusNotFound) CaptchaRequired = New(1015, "captcha_required", http.StatusForbidden) UnknownCaptchaType = New(1016, "unknown_captcha_type", http.StatusBadRequest) + TokenOutdated = New(1017, "token_outdated", http.StatusForbidden) ) func New(code int, message string, status int) *APIError { diff --git a/pkg/api/manage.go b/pkg/api/manage.go index 77ffd2f..4b5ba93 100644 --- a/pkg/api/manage.go +++ b/pkg/api/manage.go @@ -2,12 +2,15 @@ package api import ( "fmt" + "net/http" + + "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" + "github.com/ProtocolONE/auth1.protocol.one/pkg/captcha" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/labstack/echo/v4" - "net/http" ) func InitManage(cfg *Server) error { @@ -15,11 +18,17 @@ func InitManage(cfg *Server) error { return func(c echo.Context) error { db := c.Get("database").(database.MgoSession) c.Set("manage_manager", manager.NewManageManager(db, cfg.Registry)) + c.Set("password_manager", manager.NewChangePasswordManager(db, cfg.Registry, cfg.ServerConfig)) + c.Set("recaptcha", cfg.Recaptcha) return next(c) } }) + g.POST("/password/reset", passwordReset) + g.GET("/password/reset/link", passwordResetCheck) + g.GET("/password/reset/set", passwordResetSet) + g.POST("/space", createSpace) g.PUT("/space/:id", updateSpace) g.GET("/space/:id", getSpace) @@ -39,6 +48,101 @@ func InitManage(cfg *Server) error { return nil } +// Password Reset + +func passwordReset(ctx echo.Context) error { + var r struct { + Token string `query:"token" r:"token" validate:"required" json:"token"` + Action string `query:"action" r:"action" validate:"required" json:"action"` + Challenge string `query:"challenge" r:"challenge" validate:"required" json:"challenge"` + Email string `query:"email" r:"email" validate:"required" json:"email"` + } + + if err := ctx.Bind(&r); err != nil { + return apierror.InvalidRequest(err) + } + if err := ctx.Validate(r); err != nil { + return apierror.InvalidParameters(err) + } + + recaptcha := ctx.Get("recaptcha").(*captcha.Recaptcha) + ok, err := recaptcha.Verify(ctx.Request().Context(), r.Token, r.Action, "") + if err != nil { + return apierror.Unknown(err) + } + if !ok { + return apierror.CaptchaRequired + } + + m := ctx.Get("password_manager").(*manager.ChangePasswordManager) + form := &models.ChangePasswordStartForm{ + ClientID: r.Challenge, + Email: r.Email, + } + if err := m.ChangePasswordStart(form); err != nil { + ctx.Error(err.Err) + return apierror.Unknown(err) + } + + return ctx.NoContent(http.StatusNoContent) +} + +func passwordResetCheck(ctx echo.Context) error { + var form struct { + Token string `query:"token" form:"token" validate:"required" json:"token"` + Challenge string `query:"challenge" form:"challenge" validate:"required" json:"challenge"` + } + + if err := ctx.Bind(&form); err != nil { + return apierror.InvalidRequest(err) + } + if err := ctx.Validate(form); err != nil { + return apierror.InvalidParameters(err) + } + + m := ctx.Get("password_manager").(*manager.ChangePasswordManager) + if err := m.ChangePasswordCheck(form.Challenge, form.Token); err != nil { + return apierror.TokenOutdated + } + + return ctx.NoContent(http.StatusNoContent) +} + +func passwordResetSet(ctx echo.Context) error { + var form struct { + Challenge string `query:"challenge" form:"challenge" validate:"required" json:"challenge"` + Token string `query:"token" form:"token" validate:"required" json:"token"` + Password string `query:"password" form:"password" validate:"required" json:"password"` + } + + if err := ctx.Bind(&form); err != nil { + return apierror.InvalidRequest(err) + } + if err := ctx.Validate(form); err != nil { + return apierror.InvalidParameters(err) + } + + m := ctx.Get("password_manager").(*manager.ChangePasswordManager) + f := &models.ChangePasswordVerifyForm{ + ClientID: form.Challenge, + Token: form.Token, + Password: form.Password, + PasswordRepeat: form.Password, + } + if err := m.ChangePasswordVerify(f); err != nil { + return apierror.Unknown(err) + } + + // todo: logout & drop sessions + + // return URL to login + return ctx.JSON(http.StatusOK, map[string]interface{}{ + "url": "", + }) +} + +// Manage + func createSpace(ctx echo.Context) error { form := &models.SpaceForm{} m := ctx.Get("manage_manager").(*manager.ManageManager) diff --git a/pkg/manager/change_password.go b/pkg/manager/change_password.go index 8f0147f..616afa5 100644 --- a/pkg/manager/change_password.go +++ b/pkg/manager/change_password.go @@ -1,7 +1,11 @@ package manager import ( + "bytes" "fmt" + "io/ioutil" + "text/template" + "github.com/ProtocolONE/auth1.protocol.one/pkg/config" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" @@ -9,8 +13,6 @@ import ( "github.com/ProtocolONE/auth1.protocol.one/pkg/validator" "github.com/globalsign/mgo/bson" "github.com/pkg/errors" - "io/ioutil" - "strings" ) // ChangePasswordManagerInterface describes of methods for the manager. @@ -73,10 +75,30 @@ func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordS return &models.GeneralError{Code: "common", Message: models.ErrorUnableCreateOttSettings, Err: errors.Wrap(err, "Unable to create OneTimeToken")} } + // user_name, platform_name, reset_link, support_portal_url b, err := ioutil.ReadFile("./public/templates/email/change_password.html") - body := strings.ReplaceAll(string(b), "{{code}}", token.Token) - fmt.Println(body) - if err := m.r.Mailer().Send(form.Email, "Change password token", body); err != nil { + tmpl, err := template.New("mail").Parse(string(b)) + if err != nil { + // todo: fix params + return &models.GeneralError{Code: "internal"} + } + w := bytes.Buffer{} + err = tmpl.Execute(&w, struct { + UserName string + PlatformName string + Token string + SupportPortalUrl string + }{ + UserName: "", + PlatformName: "", + Token: token.Token, + SupportPortalUrl: "", + }) + if err != nil { + return &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to build reset password mail")} + } + fmt.Println(w.String()) + if err := m.r.Mailer().Send(form.Email, "Change password token", w.String()); err != nil { return &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to send mail with change password token")} } @@ -127,3 +149,20 @@ func (m *ChangePasswordManager) ChangePasswordVerify(form *models.ChangePassword return nil } + +func (m *ChangePasswordManager) ChangePasswordCheck(clientID, token string) *models.GeneralError { + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientID)) + if err != nil { + return &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} + } + + ottSettings := &models.OneTimeTokenSettings{ + Length: app.PasswordSettings.TokenLength, + TTL: app.PasswordSettings.TokenTTL, + } + if err := m.r.OneTimeTokenService().Get(token, ottSettings); err != nil { + return &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} + } + + return nil +} diff --git a/public/templates/email/change_password_2.html b/public/templates/email/change_password_2.html index dd18894..2c9ea73 100644 --- a/public/templates/email/change_password_2.html +++ b/public/templates/email/change_password_2.html @@ -175,10 +175,10 @@ style="font-size: 15px; line-height: 1.5; word-break: break-word; text-align: left; font-family: Roboto, Tahoma, Verdana, Segoe, sans-serif; mso-line-height-alt: 23px; margin: 0;" > Hi {{user_name}},Hi {{.UserName}},
Click the button to reset your password for - your {{platform_name}} account.

@@ -191,7 +191,7 @@ > {{reset_link}}{{.ResetLink}}
Need help?

{{support_portal_url}}{{.SupportPortalUrl}}

From ac33b6328556f17ccc9f526cebc0ffcd83390bc6 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Fri, 21 Feb 2020 17:34:30 +0300 Subject: [PATCH 060/251] captcha action in singup --- pkg/manager/oauth2.go | 4 ++-- pkg/models/oauth2.go | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 4b3416c..e8fae93 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -401,8 +401,8 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( } if app.RequiresCaptcha { - if form.Captcha != "" { - ok, err := m.recaptcha.Verify(context.TODO(), form.Captcha, "", "") // TODO ip, action + if form.CaptchaToken != "" { + ok, err := m.recaptcha.Verify(context.TODO(), form.CaptchaToken, form.CaptchaAction, "") // TODO ip if err != nil { return "", errors.Wrap(err, "can't verify captcha token") } diff --git a/pkg/models/oauth2.go b/pkg/models/oauth2.go index 1d8a005..20df8d1 100644 --- a/pkg/models/oauth2.go +++ b/pkg/models/oauth2.go @@ -168,8 +168,11 @@ type Oauth2SignUpForm struct { // Remember is the option for the save user session in the cookie. Remember bool `query:"remember" form:"remember"` - // Captcha is optional captcha token for real user validation - Captcha string `query:"captcha" form:"captcha"` + // CaptchaToken is optional captcha token for real user validation + CaptchaToken string `query:"captchaToken" form:"captchaToken"` + + // CaptchaAction is optional captcha action for real user validation + CaptchaAction string `query:"captchaAction" form:"captchaAction"` } func (a *Oauth2SignUpForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { From fc0e890d0372ac6ffae12c56ea02fdb8b1bcd601 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Tue, 25 Feb 2020 14:47:55 +0300 Subject: [PATCH 061/251] add captcha vars to helm --- .helm/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.helm/values.yaml b/.helm/values.yaml index 49b08a1..ff91379 100644 --- a/.helm/values.yaml +++ b/.helm/values.yaml @@ -58,6 +58,8 @@ backend: - AUTHONE_MAILER_SKIP_VERIFY - AUTHONE_MIGRATION_DIRECT - AUTHONE_AUTH_WEB_FORM_SDK_URL + - AUTHONE_RECAPTCHA_KEY + - AUTHONE_RECAPTCHA_SECRET hydra: env: From 698865220139858cd2acc5cb125e96bf224cedc8 Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Wed, 26 Feb 2020 10:54:24 +0300 Subject: [PATCH 062/251] provider apis --- pkg/api/login.go | 57 +++++++++++++++++++++++- pkg/manager/login.go | 104 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/pkg/api/login.go b/pkg/api/login.go index ce495f8..3a95ab0 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -9,6 +9,7 @@ import ( "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/labstack/echo/v4" ) @@ -25,12 +26,66 @@ func InitLogin(cfg *Server) error { }) g.GET("/link", authorizeLink) - g.GET("/result", authorizeResult) + // g.GET("/result", authorizeResult) g.GET("", authorize) + s := NewSocial(cfg.Registry) + g.GET("/result", s.Callback) + cfg.Echo.GET("/api/provider/:name/forward", s.Forward) + return nil } +type Social struct { + registry service.InternalRegistry +} + +func NewSocial(r service.InternalRegistry) *Social { + return &Social{r} +} + +func (s *Social) Forward(ctx echo.Context) error { + var ( + name = ctx.Param("name") + challenge = ctx.QueryParam("login_challenge") + domain = fmt.Sprintf("%s://%s", ctx.Scheme(), ctx.Request().Host) + ) + + db := ctx.Get("database").(database.MgoSession) + m := manager.NewLoginManager(db, s.registry) + + url, err := m.ForwardUrl(challenge, name, domain) + if err != nil { + return err + } + + return ctx.Redirect(http.StatusPermanentRedirect, url) +} + +func (s *Social) Callback(ctx echo.Context) error { + var ( + req struct { + Code string `query:"code"` + State string `query:"state"` + } + domain = fmt.Sprintf("%s://%s", ctx.Scheme(), ctx.Request().Host) + ) + + db := ctx.Get("database").(database.MgoSession) + m := manager.NewLoginManager(db, s.registry) + + if err := ctx.Bind(&req); err != nil { + return apierror.InvalidRequest(err) + } + + url, err := m.Callback("facebook", req.Code, req.State, domain) + if err != nil { + return err + } + + return ctx.Redirect(http.StatusTemporaryRedirect, url) +} + func authorize(ctx echo.Context) error { form := new(models.AuthorizeForm) m := ctx.Get("login_manager").(*manager.LoginManager) diff --git a/pkg/manager/login.go b/pkg/manager/login.go index 77dff28..e98127e 100644 --- a/pkg/manager/login.go +++ b/pkg/manager/login.go @@ -1,6 +1,7 @@ package manager import ( + "context" "encoding/base64" "encoding/json" "fmt" @@ -46,6 +47,10 @@ type LoginManagerInterface interface { // // If the user refused to link, then a new account will be created. AuthorizeLink(echo.Context, *models.AuthorizeLinkForm) (string, *models.GeneralError) + + ForwardUrl(challenge, provider, domain string) (string, error) + + Callback(provider, code, state, domain string) (string, error) } // LoginManager is the login manager. @@ -72,6 +77,105 @@ func NewLoginManager(h database.MgoSession, r service.InternalRegistry) LoginMan return m } +type State struct { + Challenge string `json:"challenge` +} + +func (m *LoginManager) Callback(provider, code, state, domain string) (string, error) { + data, err := base64.StdEncoding.DecodeString(state) + if err != nil { + return "", errors.Wrap(err, "unable to decode state param") + } + + var s State + if err := json.Unmarshal(data, &s); err != nil { + return "", errors.Wrap(err, "unable to unmarshal state") + } + + req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: s.Challenge, Context: context.TODO()}) + if err != nil { + return "", errors.Wrap(err, "can't get challenge data") + } + + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(req.Payload.Client.ClientID)) + if err != nil { + return "", errors.Wrap(err, "can't get app data") + } + + ip := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypeSocial, provider) + if ip == nil { + return "", errors.New("identity provider not found") + } + + clientProfile, err := m.identityProviderService.GetSocialProfile(context.TODO(), domain, code, ip) + if err != nil || clientProfile == nil || clientProfile.ID == "" { + if err == nil { + err = errors.New("unable to load identity profile data") + } + return "", err + } + + userIdentity, err := m.userIdentityService.Get(app, ip, clientProfile.ID) + if err != nil && err != mgo.ErrNotFound { + return "", errors.Wrap(err, "can't get user data") + } + + if userIdentity != nil && err != mgo.ErrNotFound { + + id := userIdentity.UserID.Hex() + // TODO sucessfully login + reqACL, err := m.r.HydraAdminApi().AcceptLoginRequest(&admin.AcceptLoginRequestParams{ + Context: context.TODO(), + Challenge: s.Challenge, + Body: &models2.HandledLoginRequest{Subject: &id, Remember: false, RememberFor: 0}, // TODO remember + }) + if err != nil { + return "", errors.Wrap(err, "unable to accept login challenge") + } + + return reqACL.Payload.RedirectTo, nil + } + + if clientProfile.Email != "" { + ipPass := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) + if ipPass == nil { + return "", errors.New("default identity provider not found") + } + + userIdentity, err := m.userIdentityService.Get(app, ipPass, clientProfile.Email) + if err != nil && err != mgo.ErrNotFound { + return "", errors.Wrap(err, "unable to get user identity") + } + + if userIdentity != nil && err != mgo.ErrNotFound { + // TODO user context + return fmt.Sprintf("%s/social-existing/%s?login_challenge=%s", domain, provider, s.Challenge), nil + } + } + + // TODO store profile in context + return fmt.Sprintf("%s/social-new/%s?login_challenge=%s", domain, provider, s.Challenge), nil +} + +func (m *LoginManager) ForwardUrl(challenge, provider, domain string) (string, error) { + req, err := m.r.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: challenge, Context: context.TODO()}) + if err != nil { + return "", errors.Wrap(err, "can't get challenge data") + } + + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(req.Payload.Client.ClientID)) + if err != nil { + return "", errors.Wrap(err, "can't get app data") + } + + ip := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypeSocial, provider) + if ip == nil { + return "", errors.New("identity provider not found") + } + + return m.identityProviderService.GetAuthUrl(domain, ip, &State{Challenge: challenge}) +} + func (m *LoginManager) Authorize(ctx echo.Context, form *models.AuthorizeForm) (string, *models.GeneralError) { app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(form.ClientID)) if err != nil { From 193db09befd209803b6440958ec89a3ed3da5e3d Mon Sep 17 00:00:00 2001 From: Serge Date: Wed, 26 Feb 2020 12:57:18 +0500 Subject: [PATCH 063/251] fix: fixed login challenge flow and clientid --- pkg/api/change_password.go | 3 +- pkg/api/manage.go | 37 +- pkg/api/oauth2.go | 5 +- pkg/manager/change_password.go | 35 +- pkg/manager/change_password_test.go | 3 +- pkg/manager/oauth2_test.go | 2 +- pkg/models/change_password.go | 4 +- pkg/models/mfa.go | 2 +- pkg/models/oauth2.go | 18 +- pkg/models/passwordless.go | 4 +- pkg/models/user.go | 2 +- public/templates/email/change_password.html | 620 ++++++++++-------- public/templates/email/change_password_2.html | 382 ----------- public/templates/oauth_consent.html | 2 +- public/templates/oauth_login.html | 2 +- 15 files changed, 420 insertions(+), 701 deletions(-) delete mode 100644 public/templates/email/change_password_2.html diff --git a/pkg/api/change_password.go b/pkg/api/change_password.go index 3520c72..9b38123 100644 --- a/pkg/api/change_password.go +++ b/pkg/api/change_password.go @@ -2,12 +2,13 @@ package api import ( "fmt" + "net/http" + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/labstack/echo/v4" - "net/http" ) func InitChangePassword(cfg *Server) error { diff --git a/pkg/api/manage.go b/pkg/api/manage.go index 4b5ba93..cea292f 100644 --- a/pkg/api/manage.go +++ b/pkg/api/manage.go @@ -5,12 +5,13 @@ import ( "net/http" "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" - "github.com/ProtocolONE/auth1.protocol.one/pkg/captcha" "github.com/ProtocolONE/auth1.protocol.one/pkg/database" "github.com/ProtocolONE/auth1.protocol.one/pkg/helper" "github.com/ProtocolONE/auth1.protocol.one/pkg/manager" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/labstack/echo/v4" + "github.com/ory/hydra/sdk/go/hydra/client/admin" ) func InitManage(cfg *Server) error { @@ -20,6 +21,7 @@ func InitManage(cfg *Server) error { c.Set("manage_manager", manager.NewManageManager(db, cfg.Registry)) c.Set("password_manager", manager.NewChangePasswordManager(db, cfg.Registry, cfg.ServerConfig)) c.Set("recaptcha", cfg.Recaptcha) + c.Set("registry", cfg.Registry) return next(c) } @@ -65,18 +67,28 @@ func passwordReset(ctx echo.Context) error { return apierror.InvalidParameters(err) } - recaptcha := ctx.Get("recaptcha").(*captcha.Recaptcha) - ok, err := recaptcha.Verify(ctx.Request().Context(), r.Token, r.Action, "") - if err != nil { - return apierror.Unknown(err) - } + //recaptcha := ctx.Get("recaptcha").(*captcha.Recaptcha) + //ok, err := recaptcha.Verify(ctx.Request().Context(), r.Token, r.Action, "") + //if err != nil { + // return apierror.Unknown(err) + //} + //if !ok { + // return apierror.CaptchaRequired + //} + + registry, ok := ctx.Get("registry").(service.InternalRegistry) if !ok { - return apierror.CaptchaRequired + println("Cannot cast to registry") + return apierror.Unknown(nil) + } + req, err := registry.HydraAdminApi().GetLoginRequest(&admin.GetLoginRequestParams{Challenge: r.Challenge, Context: ctx.Request().Context()}) + if err != nil { + return apierror.InvalidChallenge } m := ctx.Get("password_manager").(*manager.ChangePasswordManager) form := &models.ChangePasswordStartForm{ - ClientID: r.Challenge, + ClientID: req.Payload.Client.ClientID, Email: r.Email, } if err := m.ChangePasswordStart(form); err != nil { @@ -101,11 +113,15 @@ func passwordResetCheck(ctx echo.Context) error { } m := ctx.Get("password_manager").(*manager.ChangePasswordManager) - if err := m.ChangePasswordCheck(form.Challenge, form.Token); err != nil { + + email, err := m.ChangePasswordCheck(form.Token) + if err != nil { return apierror.TokenOutdated } - return ctx.NoContent(http.StatusNoContent) + return ctx.JSON(http.StatusOK, map[string]string{ + "email": email, + }) } func passwordResetSet(ctx echo.Context) error { @@ -124,7 +140,6 @@ func passwordResetSet(ctx echo.Context) error { m := ctx.Get("password_manager").(*manager.ChangePasswordManager) f := &models.ChangePasswordVerifyForm{ - ClientID: form.Challenge, Token: form.Token, Password: form.Password, PasswordRepeat: form.Password, diff --git a/pkg/api/oauth2.go b/pkg/api/oauth2.go index 74178a4..cdbdf62 100644 --- a/pkg/api/oauth2.go +++ b/pkg/api/oauth2.go @@ -69,7 +69,6 @@ func oauthLogin(ctx echo.Context) error { return ctx.Render(http.StatusOK, "oauth_login.html", map[string]interface{}{ "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, "AuthDomain": ctx.Scheme() + "://" + ctx.Request().Host, - "Challenge": form.Challenge, "ClientID": appID, "PreviousLogin": previousLogin, "SocProviders": socProviders, @@ -130,7 +129,7 @@ func oauthConsent(ctx echo.Context) error { return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, - "Challenge": form.Challenge, + "ClientID": form.Challenge, "Scopes": scopes, }) } @@ -152,7 +151,7 @@ func oauthConsentSubmit(ctx echo.Context) error { if err != nil { return ctx.Render(http.StatusOK, "oauth_consent.html", map[string]interface{}{ "AuthWebFormSdkUrl": m.ApiCfg.AuthWebFormSdkUrl, - "Challenge": form.Challenge, + "ClientID": form.Challenge, "Scope": m.GetScopes(form.Scope), "Error": err.Error(), }) diff --git a/pkg/manager/change_password.go b/pkg/manager/change_password.go index 616afa5..ffa5f19 100644 --- a/pkg/manager/change_password.go +++ b/pkg/manager/change_password.go @@ -46,6 +46,7 @@ func NewChangePasswordManager(db database.MgoSession, ir service.InternalRegistr } func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordStartForm) *models.GeneralError { + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(form.ClientID)) if err != nil { return &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} @@ -70,7 +71,7 @@ func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordS Length: app.PasswordSettings.TokenLength, TTL: app.PasswordSettings.TokenTTL, } - token, err := m.r.OneTimeTokenService().Create(&models.ChangePasswordTokenSource{Email: form.Email}, ottSettings) + token, err := m.r.OneTimeTokenService().Create(&models.ChangePasswordTokenSource{Email: form.Email, ClientID: form.ClientID}, ottSettings) if err != nil { return &models.GeneralError{Code: "common", Message: models.ErrorUnableCreateOttSettings, Err: errors.Wrap(err, "Unable to create OneTimeToken")} } @@ -87,11 +88,13 @@ func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordS UserName string PlatformName string Token string + Challenge string SupportPortalUrl string }{ UserName: "", PlatformName: "", Token: token.Token, + Challenge: form.ClientID, SupportPortalUrl: "", }) if err != nil { @@ -110,7 +113,12 @@ func (m *ChangePasswordManager) ChangePasswordVerify(form *models.ChangePassword return &models.GeneralError{Code: "password_repeat", Message: models.ErrorPasswordRepeat, Err: errors.New(models.ErrorPasswordRepeat)} } - app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(form.ClientID)) + ts := &models.ChangePasswordTokenSource{} + if err := m.r.OneTimeTokenService().Use(form.Token, ts); err != nil { + return &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} + } + + app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(ts.ClientID)) if err != nil { return &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} } @@ -119,11 +127,6 @@ func (m *ChangePasswordManager) ChangePasswordVerify(form *models.ChangePassword return &models.GeneralError{Code: "password", Message: models.ErrorPasswordIncorrect, Err: errors.New(models.ErrorPasswordIncorrect)} } - ts := &models.ChangePasswordTokenSource{} - if err := m.r.OneTimeTokenService().Use(form.Token, ts); err != nil { - return &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} - } - ipc := m.identityProviderService.FindByTypeAndName(app, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault) if ipc == nil { return &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.New("Unable to get identity provider")} @@ -150,19 +153,11 @@ func (m *ChangePasswordManager) ChangePasswordVerify(form *models.ChangePassword return nil } -func (m *ChangePasswordManager) ChangePasswordCheck(clientID, token string) *models.GeneralError { - app, err := m.r.ApplicationService().Get(bson.ObjectIdHex(clientID)) - if err != nil { - return &models.GeneralError{Code: "client_id", Message: models.ErrorClientIdIncorrect, Err: errors.Wrap(err, "Unable to load application")} - } - - ottSettings := &models.OneTimeTokenSettings{ - Length: app.PasswordSettings.TokenLength, - TTL: app.PasswordSettings.TokenTTL, - } - if err := m.r.OneTimeTokenService().Get(token, ottSettings); err != nil { - return &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} +func (m *ChangePasswordManager) ChangePasswordCheck(token string) (string, *models.GeneralError) { + ts := &models.ChangePasswordTokenSource{} + if err := m.r.OneTimeTokenService().Get(token, ts); err != nil { + return "", &models.GeneralError{Code: "common", Message: models.ErrorCannotUseToken, Err: errors.Wrap(err, "Unable to use OneTimeToken")} } - return nil + return ts.Email, nil } diff --git a/pkg/manager/change_password_test.go b/pkg/manager/change_password_test.go index f2f7b5b..fc7beac 100644 --- a/pkg/manager/change_password_test.go +++ b/pkg/manager/change_password_test.go @@ -1,6 +1,8 @@ package manager import ( + "testing" + "github.com/ProtocolONE/auth1.protocol.one/pkg/mocks" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/globalsign/mgo" @@ -8,7 +10,6 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "testing" ) func TestChangePasswordManager(t *testing.T) { diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index 5375e5a..30fcac5 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -908,7 +908,7 @@ func TestSignUpReturnErrorWithUnableToGetLoginChallenge(t *testing.T) { // r: r, // session: s, // } -// _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", Challenge: "login_challenge"}) +// _, err := m.SignUp(getContext(), &models.Oauth2SignUpForm{Remember: true, Password: "11", ClientID: "login_challenge"}) // fmt.Println(err) // assert.NotNil(t, err) diff --git a/pkg/models/change_password.go b/pkg/models/change_password.go index 498bdca..0f51812 100644 --- a/pkg/models/change_password.go +++ b/pkg/models/change_password.go @@ -25,6 +25,7 @@ type ChangePasswordStartForm struct { // ChangePasswordVerifyForm contains form fields for completing a password change. type ChangePasswordVerifyForm struct { + //todo: remove field? used in dbconnections/password-change and unused in /api/password/reset // ClientID is the application id ClientID string `form:"client_id" json:"client_id" validate:"required"` @@ -39,7 +40,8 @@ type ChangePasswordVerifyForm struct { } type ChangePasswordTokenSource struct { - Email string + Email string + ClientID string } func (a *ChangePasswordStartForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { diff --git a/pkg/models/mfa.go b/pkg/models/mfa.go index 86facda..fcce137 100644 --- a/pkg/models/mfa.go +++ b/pkg/models/mfa.go @@ -184,7 +184,7 @@ func (m *MfaApplicationProviderForm) MarshalLogObject(enc zapcore.ObjectEncoder) } func (m *MfaChallengeForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("ClientId", m.ClientId) + enc.AddString("ClientID", m.ClientId) enc.AddString("Name", m.Connection) enc.AddString("Type", m.Type) enc.AddString("Token", m.Token) diff --git a/pkg/models/oauth2.go b/pkg/models/oauth2.go index 20df8d1..e1529de 100644 --- a/pkg/models/oauth2.go +++ b/pkg/models/oauth2.go @@ -6,19 +6,19 @@ import ( // Oauth2LoginForm contains form fields for requesting a login form. type Oauth2LoginForm struct { - // Challenge is the code of the oauth2 login challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 login challenge. This code to generates of the Hydra service. Challenge string `query:"login_challenge" form:"login_challenge" validate:"required"` } func (a *Oauth2LoginForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("Challenge", a.Challenge) + enc.AddString("ClientID", a.Challenge) return nil } // Oauth2LoginSubmitForm contains form fields for submit login form. type Oauth2LoginSubmitForm struct { - // Challenge is the code of the oauth2 login challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 login challenge. This code to generates of the Hydra service. Challenge string `query:"challenge" form:"challenge" validate:"required"` // Email is the email address of user for login request. @@ -40,19 +40,19 @@ type Oauth2LoginSubmitForm struct { // Oauth2ConsentForm contains form fields for request of consent. type Oauth2ConsentForm struct { - // Challenge is the code of the oauth2 consent challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 consent challenge. This code to generates of the Hydra service. Challenge string `query:"consent_challenge" form:"consent_challenge" validate:"required"` } func (a *Oauth2ConsentForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("Challenge", a.Challenge) + enc.AddString("ClientID", a.Challenge) return nil } // Oauth2ConsentSubmitForm contains form fields for submit consent form. type Oauth2ConsentSubmitForm struct { - // Challenge is the code of the oauth2 consent challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 consent challenge. This code to generates of the Hydra service. Challenge string `query:"challenge" form:"challenge" validate:"required"` // Scope is a list of scopes that the user has taken. @@ -60,7 +60,7 @@ type Oauth2ConsentSubmitForm struct { } func (a *Oauth2LoginSubmitForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("Challenge", a.Challenge) + enc.AddString("ClientID", a.Challenge) enc.AddString("Email", a.Email) enc.AddString("Password", "[HIDDEN]") @@ -153,7 +153,7 @@ type Oauth2TokenIntrospection struct { // Oauth2SignUpForm contains form fields for request signup form. type Oauth2SignUpForm struct { - // Challenge is the code of the oauth2 login challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 login challenge. This code to generates of the Hydra service. Challenge string `query:"challenge" form:"challenge" validate:"required"` // Username represent user nickname, optional. @@ -176,7 +176,7 @@ type Oauth2SignUpForm struct { } func (a *Oauth2SignUpForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("Challenge", a.Challenge) + enc.AddString("ClientID", a.Challenge) enc.AddString("Username", a.Username) enc.AddString("Email", a.Email) enc.AddString("Password", "[HIDDEN]") diff --git a/pkg/models/passwordless.go b/pkg/models/passwordless.go index fcbaed7..92e85e5 100644 --- a/pkg/models/passwordless.go +++ b/pkg/models/passwordless.go @@ -15,14 +15,14 @@ type PasswordLessVerifyForm struct { } func (m *PasswordLessStartForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("ClientId", m.ClientId) + enc.AddString("ClientID", m.ClientId) enc.AddString("Name", m.Connection) return nil } func (m *PasswordLessVerifyForm) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("ClientId", m.ClientId) + enc.AddString("ClientID", m.ClientId) enc.AddString("Name", m.Connection) enc.AddString("Code", m.Code) enc.AddString("Token", m.Token) diff --git a/pkg/models/user.go b/pkg/models/user.go index ae913bd..e795468 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -93,7 +93,7 @@ type AuthorizeResultResponse struct { } type AuthorizeLinkForm struct { - // Challenge is the code of the oauth2 login challenge. This code to generates of the Hydra service. + // ClientID is the code of the oauth2 login challenge. This code to generates of the Hydra service. Challenge string `query:"challenge" form:"challenge" json:"challenge" validate:"required"` // ClientID is the id of the application. diff --git a/public/templates/email/change_password.html b/public/templates/email/change_password.html index 0cb10ac..ea33a8f 100644 --- a/public/templates/email/change_password.html +++ b/public/templates/email/change_password.html @@ -1,294 +1,382 @@ - - - - - + + + + + + + + + + - - + - - - - - + + + + + diff --git a/public/templates/email/change_password_2.html b/public/templates/email/change_password_2.html deleted file mode 100644 index 2c9ea73..0000000 --- a/public/templates/email/change_password_2.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/templates/oauth_consent.html b/public/templates/oauth_consent.html index b6f9e85..2340205 100644 --- a/public/templates/oauth_consent.html +++ b/public/templates/oauth_consent.html @@ -4,7 +4,7 @@

Please select scopes

- + {{ range $key, $value := index . "Scopes"}} diff --git a/public/templates/oauth_login.html b/public/templates/oauth_login.html index ad98172..069aec6 100644 --- a/public/templates/oauth_login.html +++ b/public/templates/oauth_login.html @@ -16,7 +16,7 @@ + + + +`) +} + func (c *Centrifugo) Authentication(ctx echo.Context) error { println(ctx.Request().Header.Get("Authorization")) challenge, err := ctx.Request().Cookie("login_challenge") diff --git a/pkg/api/social.go b/pkg/api/social.go index a1e820d..e5ee3d8 100644 --- a/pkg/api/social.go +++ b/pkg/api/social.go @@ -200,6 +200,7 @@ func (s *Social) Callback(ctx echo.Context) error { return err } + t.Domain = domain t.UserIdentity = ui t.UserIdentitySocial = uis @@ -211,16 +212,20 @@ func (s *Social) Callback(ctx echo.Context) error { } // For Web - if ui != nil && err != mgo.ErrNotFound { - // accept login and redirect - url, err := m.Accept(ctx, ui, name, state.Challenge) - if err != nil { - return err - } - return ctx.Redirect(http.StatusTemporaryRedirect, url) - } - // UserIdentity does not exist: link or sign up - url, err := m.SocialLogin(uis, domain, name, state.Challenge) + //if ui != nil && err != mgo.ErrNotFound { + // // accept login and redirect + // url, err := m.Accept(ctx, ui, name, state.Challenge) + // if err != nil { + // return err + // } + // return ctx.Redirect(http.StatusTemporaryRedirect, url) + //} + //// UserIdentity does not exist: link or sign up + //url, err := m.SocialLogin(uis, domain, name, state.Challenge) + //if err != nil { + // return err + //} + url, err := s.accept(ctx, m, ui, uis, name, domain, state.Challenge) if err != nil { return err } @@ -286,12 +291,21 @@ func (s *Social) Confirm(ctx echo.Context) error { return err } - err = s.registry.CentrifugoService().Success(challenge, t.URL) + db := ctx.Get("database").(database.MgoSession) + m := manager.NewLoginManager(db, s.registry) + + url, err := s.accept(ctx, m, t.UserIdentity, t.UserIdentitySocial, t.Name, t.Domain, t.Challenge) + if err != nil { + return err + } + + err = s.registry.CentrifugoService().Success(challenge, url) if err != nil { return err } t.Status = "success" + t.URL = url err = s.registry.LauncherTokenService().Set(challenge, t, &models.LauncherTokenSettings{TTL: 600}) if err != nil { return err @@ -300,3 +314,12 @@ func (s *Social) Confirm(ctx echo.Context) error { "status": "success", }) } + +func (s *Social) accept(ctx echo.Context, m manager.LoginManagerInterface, ui *models.UserIdentity, uis *models.UserIdentitySocial, name, domain, challenge string) (string, error) { + if ui != nil { + // accept login and redirect + return m.Accept(ctx, ui, name, challenge) + } + // UserIdentity does not exist: link or sign up + return m.SocialLogin(uis, domain, name, challenge) +} diff --git a/pkg/models/launcher.go b/pkg/models/launcher.go index 6420d82..1943e55 100644 --- a/pkg/models/launcher.go +++ b/pkg/models/launcher.go @@ -21,6 +21,8 @@ type LauncherToken struct { UserIdentitySocial *UserIdentitySocial `json:"uis"` // Name is the name of social provider Name string `json:"name"` + // Domain stores domain name + Domain string `json:"domain"` // Status stores state of the login process Status string `json:"status"` // URL to finish From 9ae686c98f6a8ae545609338307db3125744d2d5 Mon Sep 17 00:00:00 2001 From: Serge Date: Fri, 3 Apr 2020 20:17:38 +0500 Subject: [PATCH 177/251] fix: fixed error logging and error type --- pkg/api/social.go | 3 +++ pkg/models/launcher.go | 4 ++++ pkg/service/launcher_token.go | 3 +-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/api/social.go b/pkg/api/social.go index e5ee3d8..16024e3 100644 --- a/pkg/api/social.go +++ b/pkg/api/social.go @@ -263,6 +263,9 @@ func (s *Social) Check(ctx echo.Context) error { err := s.registry.LauncherTokenService().Get(loginChallenge, t) if err != nil { + if err != models.LauncherToken_NotFound { + ctx.Logger().Error(err.Error()) + } return ctx.JSON(http.StatusOK, response{ Status: "expired", }) diff --git a/pkg/models/launcher.go b/pkg/models/launcher.go index 1943e55..dbe11bf 100644 --- a/pkg/models/launcher.go +++ b/pkg/models/launcher.go @@ -1,5 +1,7 @@ package models +import "errors" + // LauncherTokenSettings contains settings for stored launcher token. type LauncherTokenSettings struct { //TTL is the expiration time for the token. @@ -28,3 +30,5 @@ type LauncherToken struct { // URL to finish URL string `json:"url"` } + +var LauncherToken_NotFound = errors.New("launcher token not found") diff --git a/pkg/service/launcher_token.go b/pkg/service/launcher_token.go index f4093f2..92560b8 100644 --- a/pkg/service/launcher_token.go +++ b/pkg/service/launcher_token.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/go-redis/redis" ) @@ -57,7 +56,7 @@ func (s *LauncherTokenService) Get(key string, obj interface{}) error { res, err := s.Redis.Get(fmt.Sprintf(LauncherTokenStoragePattern, key)).Bytes() if err != nil { if err == redis.Nil { - return apierror.NotFound + return models.LauncherToken_NotFound } return err } From 691f5ad6b99fa3cfc3e4a8666cae19fd2a2ab3d3 Mon Sep 17 00:00:00 2001 From: Serge Date: Fri, 3 Apr 2020 20:28:35 +0500 Subject: [PATCH 178/251] fix: removed tmp code --- pkg/api/centrifugo.go | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/pkg/api/centrifugo.go b/pkg/api/centrifugo.go index e4b951f..0babcbe 100644 --- a/pkg/api/centrifugo.go +++ b/pkg/api/centrifugo.go @@ -15,7 +15,6 @@ import ( func InitCentrifugo(cfg *Server) error { c := NewCentrifugo(cfg) - cfg.Echo.GET("/api/ws", c.Html) cfg.Echo.POST("/centrifugo/auth", c.Authentication) cfg.Echo.POST("/centrifugo/refresh", c.Refresh) @@ -35,32 +34,6 @@ func NewCentrifugo(cfg *Server) *Centrifugo { } } -func (c *Centrifugo) Html(ctx echo.Context) error { - ch := ctx.QueryParam("ch") - return ctx.HTML(http.StatusOK, ` - - - - - - - - -`) -} - func (c *Centrifugo) Authentication(ctx echo.Context) error { println(ctx.Request().Header.Get("Authorization")) challenge, err := ctx.Request().Cookie("login_challenge") From d95a3e4abc3bafa28f6538643d17531f6549a8b1 Mon Sep 17 00:00:00 2001 From: Serge Date: Mon, 6 Apr 2020 15:46:28 +0500 Subject: [PATCH 179/251] refactor: restored code lost on merge --- pkg/api/social.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/pkg/api/social.go b/pkg/api/social.go index 16024e3..d5680b0 100644 --- a/pkg/api/social.go +++ b/pkg/api/social.go @@ -22,6 +22,7 @@ func InitSocial(cfg *Server) error { cfg.Echo.GET("/api/providers/:name/profile", s.Profile) cfg.Echo.GET("/api/providers/:name/check", s.Check) cfg.Echo.GET("/api/providers/:name/confirm", s.Confirm) + cfg.Echo.GET("/api/providers/:name/cancel", s.Cancel) cfg.Echo.POST("/api/providers/:name/link", s.Link) cfg.Echo.POST("/api/providers/:name/signup", s.Signup) // redirect based apis @@ -318,6 +319,34 @@ func (s *Social) Confirm(ctx echo.Context) error { }) } +func (s *Social) Cancel(ctx echo.Context) error { + var ( + challenge = ctx.QueryParam("login_challenge") + url = "" + ) + + t := &models.LauncherToken{} + err := s.registry.LauncherTokenService().Get(challenge, t) + if err != nil { + if err == models.LauncherToken_NotFound { + return ctx.JSON(http.StatusOK, map[string]string{ + "status": "expired", + }) + } + return err + } + + t.Status = models.LauncherAuth_Canceled + t.URL = url + err = s.registry.LauncherTokenService().Set(challenge, t, &models.LauncherTokenSettings{TTL: 600}) + if err != nil { + return err + } + return ctx.JSON(http.StatusOK, map[string]string{ + "status": "success", + }) +} + func (s *Social) accept(ctx echo.Context, m manager.LoginManagerInterface, ui *models.UserIdentity, uis *models.UserIdentitySocial, name, domain, challenge string) (string, error) { if ui != nil { // accept login and redirect From 97363fc21d66bbf5695db56731c951a4a99e3376 Mon Sep 17 00:00:00 2001 From: Serge Date: Mon, 6 Apr 2020 16:13:03 +0500 Subject: [PATCH 180/251] refactor: restored code lost on merge --- pkg/api/social.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/api/social.go b/pkg/api/social.go index d5680b0..0340732 100644 --- a/pkg/api/social.go +++ b/pkg/api/social.go @@ -292,9 +292,20 @@ func (s *Social) Confirm(ctx echo.Context) error { t := &models.LauncherToken{} err := s.registry.LauncherTokenService().Get(challenge, t) if err != nil { + if err == models.LauncherToken_NotFound { + return ctx.JSON(http.StatusOK, map[string]string{ + "status": "canceled", + }) + } return err } + if t.Status == models.LauncherAuth_Canceled { + return ctx.JSON(http.StatusOK, map[string]string{ + "status": "canceled", + }) + } + db := ctx.Get("database").(database.MgoSession) m := manager.NewLoginManager(db, s.registry) From 2b18e85d5172f146576d4d7ff9742f01fad74843 Mon Sep 17 00:00:00 2001 From: Serge Date: Wed, 8 Apr 2020 19:56:51 +0500 Subject: [PATCH 181/251] fix: fixed type cast --- go.mod | 1 + pkg/manager/oauth2.go | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 954d32b..6a88dcb 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff github.com/centrifugal/gocent v2.1.0+incompatible + github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/go-openapi/runtime v0.19.11 diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 72d425c..8307b33 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -303,21 +303,23 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen if err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get consent challenge")} } - user, err := m.userService.Get(bson.ObjectIdHex(reqGCR.Payload.Subject)) if err != nil { return "", &models.GeneralError{Code: "email", Message: models.ErrorLoginIncorrect, Err: errors.Wrap(err, "Unable to get user")} } - remember := true if reqGCR.Payload.Skip == true { r, err := m.session.Get(ctx, loginRememberKey) if err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get session")} } - remember = r.(bool) + okRemember, ok := r.(bool) + if !ok { + remember = false + } else { + remember = okRemember + } } - userInfo := map[string]interface{}{ "email": user.Email, "email_verified": user.EmailVerified, @@ -339,7 +341,6 @@ func (m *OauthManager) ConsentSubmit(ctx echo.Context, form *models.Oauth2Consen if err != nil { return "", &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to accept consent challenge")} } - return reqACR.Payload.RedirectTo, nil } From 168a215a042f46fa1fbe544de62ed8dc512d3266 Mon Sep 17 00:00:00 2001 From: Serge Date: Fri, 10 Apr 2020 14:06:01 +0500 Subject: [PATCH 182/251] refactor: permanent to temporary redirect --- pkg/api/social.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/social.go b/pkg/api/social.go index 0340732..5023fdb 100644 --- a/pkg/api/social.go +++ b/pkg/api/social.go @@ -153,7 +153,7 @@ func (s *Social) Forward(ctx echo.Context) error { } } - return ctx.Redirect(http.StatusPermanentRedirect, url) + return ctx.Redirect(http.StatusTemporaryRedirect, url) } func (s *Social) Callback(ctx echo.Context) error { From 77190c8f39b965035433534e62d39fdf31e10fad Mon Sep 17 00:00:00 2001 From: Aleksandr Barsukov Date: Mon, 13 Apr 2020 15:36:29 +0300 Subject: [PATCH 183/251] attach users to space --- .../20200410_01_unique_users_per_space.go | 78 +++++++++++++++++++ pkg/manager/change_password.go | 4 +- pkg/manager/login.go | 6 +- pkg/manager/manage.go | 4 +- pkg/manager/mfa_test.go | 4 + pkg/manager/oauth2.go | 18 +++-- pkg/manager/oauth2_test.go | 24 +++--- .../AppIdentityProviderServiceInterface.go | 13 +++- pkg/mocks/ApplicationServiceInterface.go | 9 ++- pkg/mocks/AuthLogServiceInterface.go | 12 ++- pkg/mocks/GeoIp.go | 13 +++- pkg/mocks/HydraAdminApi.go | 9 ++- pkg/mocks/InternalRegistry.go | 28 ++++++- pkg/mocks/LauncherTokenServiceInterface.go | 6 +- pkg/mocks/MfaApiInterface.go | 13 +++- pkg/mocks/MfaServiceInterface.go | 9 ++- pkg/mocks/OneTimeTokenServiceInterface.go | 6 +- pkg/mocks/SessionService.go | 6 +- pkg/mocks/SpaceServiceInterface.go | 9 ++- pkg/mocks/UserIdentityServiceInterface.go | 53 +++++++------ pkg/mocks/UserServiceInterface.go | 19 +++-- pkg/models/space.go | 18 +++-- pkg/models/user.go | 7 +- pkg/service/registry.go | 3 + pkg/service/registry_base.go | 6 ++ pkg/service/space.go | 2 +- pkg/service/user.go | 6 +- pkg/service/user_identity.go | 16 ++-- 28 files changed, 286 insertions(+), 115 deletions(-) create mode 100644 pkg/database/migrations/20200410_01_unique_users_per_space.go diff --git a/pkg/database/migrations/20200410_01_unique_users_per_space.go b/pkg/database/migrations/20200410_01_unique_users_per_space.go new file mode 100644 index 0000000..5c05d4c --- /dev/null +++ b/pkg/database/migrations/20200410_01_unique_users_per_space.go @@ -0,0 +1,78 @@ +package migrations + +import ( + "github.com/ProtocolONE/auth1.protocol.one/pkg/database" + "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + "github.com/globalsign/mgo" + "github.com/globalsign/mgo/bson" + "github.com/pkg/errors" + "github.com/xakep666/mongo-migrate" +) + +func init() { + err := migrate.Register( + func(db *mgo.Database) error { + + var err error + var apps []*models.Application + + if err = db.C(database.TableApplication).Find(nil).All(&apps); err != nil { + return errors.Wrapf(err, "Unable to get applications") + } + + iter := db.C(database.TableUser).Repair() + var user models.User + for iter.Next(&user) { + var app = findapp(apps, user.AppID) + user.SpaceID = app.SpaceId + db.C(database.TableUser).UpdateId(user.ID, user) + + } + if err := iter.Close(); err != nil { + return errors.Wrap(err, "failed to close iterator") + } + + + + if err := db.C(database.TableUserIdentity).DropIndex("username", "app_id"); err != nil { + return errors.Wrapf(err, "Drop user identity collection `Idx-Username-AppId` index failed") + } + + db.C(database.TableUser).EnsureIndex(mgo.Index{ + Name: "Idx-Username-SpaceId", + Key: []string{"username", "space_id"}, + PartialFilter: bson.M{"uniq_username": true}, + Unique: true, + Background: true, + Sparse: false, + }) + + if err != nil { + return errors.Wrapf(err, "Ensure user identity collection `Idx-Username-SpaceId` index failed") + } + + return nil + }, + func(db *mgo.Database) error { + if err := db.C(database.TableUserIdentity).DropIndex("username", "space_id"); err != nil { + return errors.Wrapf(err, "Drop user identity collection `Idx-Username-SpaceId` index failed") + } + + return nil + }, + ) + + if err != nil { + return + } +} + + +func findapp(apps []*models.Application, id bson.ObjectId) *models.Application { + for _, a := range apps { + if a.ID == id { + return a + } + } + panic("not found") +} \ No newline at end of file diff --git a/pkg/manager/change_password.go b/pkg/manager/change_password.go index d617247..05b05c5 100644 --- a/pkg/manager/change_password.go +++ b/pkg/manager/change_password.go @@ -62,7 +62,7 @@ func (m *ChangePasswordManager) ChangePasswordStart(form *models.ChangePasswordS return &models.GeneralError{Code: "client_id", Message: models.ErrorUnknownError, Err: errors.New("Unable to get identity provider")} } - ui, err := m.userIdentityService.Get(app, ipc, form.Email) + ui, err := m.userIdentityService.Get(ipc, form.Email) if err != nil { return &models.GeneralError{Code: "email", Message: models.ErrorUnknownError, Err: errors.Wrap(err, "Unable to get user identity by email")} } @@ -139,7 +139,7 @@ func (m *ChangePasswordManager) ChangePasswordVerify(form *models.ChangePassword return &models.GeneralError{Code: "common", Message: models.ErrorUnknownError, Err: errors.New("Unable to get identity provider")} } - ui, err := m.userIdentityService.Get(app, ipc, ts.Email) + ui, err := m.userIdentityService.Get(ipc, ts.Email) if err != nil || ui.ID == "" { if err == nil { err = errors.New("User identity not found") diff --git a/pkg/manager/login.go b/pkg/manager/login.go index f186161..977425a 100644 --- a/pkg/manager/login.go +++ b/pkg/manager/login.go @@ -150,7 +150,7 @@ func (m *LoginManager) GetUserIdentities(challenge, provider, domain, code strin return nil, nil, err } - userIdentity, err := m.userIdentityService.Get(app, ip, clientProfile.ID) + userIdentity, err := m.userIdentityService.Get(ip, clientProfile.ID) if err != nil && err != mgo.ErrNotFound { return nil, nil, errors.Wrap(err, "can't get user data") } @@ -208,7 +208,7 @@ func (m *LoginManager) SocialLogin(clientProfile *models.UserIdentitySocial, dom return "", errors.New("default identity provider not found") } - userIdentity, err := m.userIdentityService.Get(app, ipPass, clientProfile.Email) + userIdentity, err := m.userIdentityService.Get(ipPass, clientProfile.Email) if err != nil && err != mgo.ErrNotFound { return "", errors.Wrap(err, "unable to get user identity") } @@ -275,7 +275,7 @@ func (m *LoginManager) Link(token string, userID bson.ObjectId, app *models.Appl } // check for already linked - _, err := m.userIdentityService.FindByUser(app, ip, userID) + _, err := m.userIdentityService.FindByUser(ip, userID) if err != mgo.ErrNotFound { if err != nil { return errors.Wrap(err, "can't search user identity info") diff --git a/pkg/manager/manage.go b/pkg/manager/manage.go index 45fc26a..224a130 100644 --- a/pkg/manager/manage.go +++ b/pkg/manager/manage.go @@ -35,7 +35,7 @@ func NewManageManager(db database.MgoSession, r service.InternalRegistry) *Manag func (m *ManageManager) CreateSpace(ctx echo.Context, form *models.SpaceForm) (*models.Space, *models.GeneralError) { s := &models.Space{ - Id: bson.NewObjectId(), + ID: bson.NewObjectId(), Name: form.Name, Description: form.Description, IsActive: form.IsActive, @@ -88,7 +88,7 @@ func (m *ManageManager) CreateApplication(ctx echo.Context, form *models.Applica appID := bson.NewObjectId() app := &models.Application{ ID: appID, - SpaceId: s.Id, + SpaceId: s.ID, Name: form.Application.Name, Description: form.Application.Description, IsActive: form.Application.IsActive, diff --git a/pkg/manager/mfa_test.go b/pkg/manager/mfa_test.go index 62b6e6f..1d0d134 100644 --- a/pkg/manager/mfa_test.go +++ b/pkg/manager/mfa_test.go @@ -22,8 +22,12 @@ func TestMFAManager(t *testing.T) { } func mockIntRegistry() *mocks.InternalRegistry { + spaces := &mocks.SpaceServiceInterface{} + spaces.On("GetSpace", mock.Anything).Return(&models.Space{}, nil) + r := &mocks.InternalRegistry{} r.On("GeoIpService").Return(nil) + r.On("SpaceService").Return(spaces) return r } diff --git a/pkg/manager/oauth2.go b/pkg/manager/oauth2.go index 8307b33..6749aa5 100644 --- a/pkg/manager/oauth2.go +++ b/pkg/manager/oauth2.go @@ -223,7 +223,7 @@ func (m *OauthManager) Auth(ctx echo.Context, form *models.Oauth2LoginSubmitForm return "", errors.New("unable to get identity provider") } - userIdentity, err = m.userIdentityService.Get(app, ipc, form.Email) + userIdentity, err = m.userIdentityService.Get(ipc, form.Email) if err != nil { return "", apierror.InvalidCredentials } @@ -438,7 +438,13 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return "", errors.Wrap(err, "unable to load application") } - if app.RequiresCaptcha && !m.lm.Check(form.Social) { // don't require captcha for social reg + space, err := m.r.SpaceService().GetSpace(app.SpaceId) + if err != nil { + return "", errors.Wrap(err, "unable to load space") + } + _ = space + + if space.RequiresCaptcha && !m.lm.Check(form.Social) { // don't require captcha for social reg if form.CaptchaToken != "" { ok, err := m.recaptcha.Verify(context.TODO(), form.CaptchaToken, form.CaptchaAction, "") // TODO ip if err != nil { @@ -458,9 +464,9 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( } } - if app.UniqueUsernames { + if space.UniqueUsernames { - free, err := m.userService.IsUsernameFree(form.Username, app.ID) + free, err := m.userService.IsUsernameFree(form.Username, space.ID) if err != nil { return "", errors.Wrap(err, "Unable to check username availability") } @@ -486,7 +492,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( return "", errors.New("unable to get identity provider") } - userIdentity, err := m.userIdentityService.Get(app, ipc, form.Email) + userIdentity, err := m.userIdentityService.Get(ipc, form.Email) if err == nil { return "", apierror.EmailRegistered } @@ -497,7 +503,7 @@ func (m *OauthManager) SignUp(ctx echo.Context, form *models.Oauth2SignUpForm) ( user := &models.User{ ID: bson.NewObjectId(), - AppID: app.ID, + SpaceID: app.SpaceId, Username: form.Username, UniqueUsername: app.UniqueUsernames, Email: form.Email, diff --git a/pkg/manager/oauth2_test.go b/pkg/manager/oauth2_test.go index de0872d..57abf7f 100644 --- a/pkg/manager/oauth2_test.go +++ b/pkg/manager/oauth2_test.go @@ -358,7 +358,7 @@ func TestAuthReturnErrorWithUnavailableUserIdentity(t *testing.T) { ott.On("Use", "invalid_auth_token", mock.Anything).Return(nil) app.On("Get", mock.Anything).Return(&models.Application{}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - uis.On("Get", mock.Anything, mock.Anything, "invalid_email").Return(nil, errors.New("")) + uis.On("Get", mock.Anything, "invalid_email").Return(nil, errors.New("")) r.On("HydraAdminApi").Return(h) r.On("ApplicationService").Return(app) r.On("OneTimeTokenService").Return(ott) @@ -388,7 +388,7 @@ func TestAuthReturnErrorWithComparePassword(t *testing.T) { ott.On("Use", "invalid_auth_token", mock.Anything).Return(nil) app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - uis.On("Get", mock.Anything, mock.Anything, "email").Return(&models.UserIdentity{Credential: "1"}, nil) + uis.On("Get", mock.Anything, "email").Return(&models.UserIdentity{Credential: "1"}, nil) r.On("HydraAdminApi").Return(h) r.On("ApplicationService").Return(app) r.On("OneTimeTokenService").Return(ott) @@ -421,7 +421,7 @@ func TestAuthReturnErrorWithUnableToGetUser(t *testing.T) { ott.On("Use", "invalid_auth_token", mock.Anything).Return(nil) app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - uis.On("Get", mock.Anything, mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) + uis.On("Get", mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) us.On("Get", mock.Anything).Return(nil, errors.New("")) r.On("HydraAdminApi").Return(h) r.On("ApplicationService").Return(app) @@ -456,7 +456,7 @@ func TestAuthReturnErrorWithUnableToUpdateUser(t *testing.T) { ott.On("Use", "invalid_auth_token", mock.Anything).Return(nil) app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - uis.On("Get", mock.Anything, mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) + uis.On("Get", mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) us.On("Get", mock.Anything).Return(&models.User{}, nil) us.On("Update", mock.Anything).Return(errors.New("")) r.On("HydraAdminApi").Return(h) @@ -493,7 +493,7 @@ func TestAuthReturnErrorWithUnableToAddAuthLog(t *testing.T) { ott.On("Use", "invalid_auth_token", mock.Anything).Return(nil) app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - uis.On("Get", mock.Anything, mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) + uis.On("Get", mock.Anything, "email").Return(&models.UserIdentity{Credential: passHash}, nil) us.On("Get", mock.Anything).Return(&models.User{}, nil) us.On("Update", mock.Anything).Return(nil) al.On("Add", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("")) @@ -975,7 +975,7 @@ func TestSignUpReturnErrorWithUnableToGetUserIdentity(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(&models.UserIdentity{}, nil) + ui.On("Get", mock.Anything, "email").Return(&models.UserIdentity{}, nil) r.On("ApplicationService").Return(app) r.On("HydraAdminApi").Return(h) @@ -1006,7 +1006,7 @@ func TestSignUpReturnErrorWithEncryptPassword(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) r.On("ApplicationService").Return(app) r.On("HydraAdminApi").Return(h) @@ -1038,7 +1038,7 @@ func TestSignUpReturnErrorWithUnableToCreateUser(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) u.On("Create", mock.Anything).Return(errors.New("")) r.On("ApplicationService").Return(app) r.On("HydraAdminApi").Return(h) @@ -1072,7 +1072,7 @@ func TestSignUpReturnErrorWithUnableToCreateUserIdentity(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) u.On("Create", mock.Anything).Return(nil) ui.On("Create", mock.Anything).Return(errors.New("")) r.On("ApplicationService").Return(app) @@ -1108,7 +1108,7 @@ func TestSignUpReturnErrorWithUnableToAddAuthLog(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) u.On("Create", mock.Anything).Return(nil) ui.On("Create", mock.Anything).Return(nil) a.On("Add", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("")) @@ -1146,7 +1146,7 @@ func TestSignUpReturnErrorWithUnableToAcceptLoginChallenge(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) u.On("Create", mock.Anything).Return(nil) ui.On("Create", mock.Anything).Return(nil) a.On("Add", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) @@ -1185,7 +1185,7 @@ func TestSignUpReturnUrlOnSuccessResponse(t *testing.T) { app.On("Get", mock.Anything).Return(&models.Application{PasswordSettings: passSettings}, nil) h.On("GetLoginRequest", mock.Anything).Return(&admin.GetLoginRequestOK{Payload: &models2.LoginRequest{Client: &models2.OAuth2Client{ClientID: clientId}}}, nil) ip.On("FindByTypeAndName", mock.Anything, models.AppIdentityProviderTypePassword, models.AppIdentityProviderNameDefault).Return(&models.AppIdentityProvider{}) - ui.On("Get", mock.Anything, mock.Anything, "email").Return(nil, errors.New("")) + ui.On("Get", mock.Anything, "email").Return(nil, errors.New("")) u.On("Create", mock.Anything).Return(nil) ui.On("Create", mock.Anything).Return(nil) a.On("Add", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) diff --git a/pkg/mocks/AppIdentityProviderServiceInterface.go b/pkg/mocks/AppIdentityProviderServiceInterface.go index 3655bba..50a080c 100644 --- a/pkg/mocks/AppIdentityProviderServiceInterface.go +++ b/pkg/mocks/AppIdentityProviderServiceInterface.go @@ -2,10 +2,15 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import context "context" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + context "context" + + bson "github.com/globalsign/mgo/bson" + + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // AppIdentityProviderServiceInterface is an autogenerated mock type for the AppIdentityProviderServiceInterface type type AppIdentityProviderServiceInterface struct { diff --git a/pkg/mocks/ApplicationServiceInterface.go b/pkg/mocks/ApplicationServiceInterface.go index f4069aa..3cbddf9 100644 --- a/pkg/mocks/ApplicationServiceInterface.go +++ b/pkg/mocks/ApplicationServiceInterface.go @@ -2,9 +2,12 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // ApplicationServiceInterface is an autogenerated mock type for the ApplicationServiceInterface type type ApplicationServiceInterface struct { diff --git a/pkg/mocks/AuthLogServiceInterface.go b/pkg/mocks/AuthLogServiceInterface.go index 9caacda..b1c7827 100644 --- a/pkg/mocks/AuthLogServiceInterface.go +++ b/pkg/mocks/AuthLogServiceInterface.go @@ -2,10 +2,14 @@ package mocks -import echo "github.com/labstack/echo/v4" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" -import service "github.com/ProtocolONE/auth1.protocol.one/pkg/service" +import ( + echo "github.com/labstack/echo/v4" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + + service "github.com/ProtocolONE/auth1.protocol.one/pkg/service" +) // AuthLogServiceInterface is an autogenerated mock type for the AuthLogServiceInterface type type AuthLogServiceInterface struct { diff --git a/pkg/mocks/GeoIp.go b/pkg/mocks/GeoIp.go index 752716c..ff78e41 100644 --- a/pkg/mocks/GeoIp.go +++ b/pkg/mocks/GeoIp.go @@ -2,10 +2,15 @@ package mocks -import client "github.com/micro/go-micro/client" -import context "context" -import mock "github.com/stretchr/testify/mock" -import proto "github.com/ProtocolONE/geoip-service/pkg/proto" +import ( + context "context" + + client "github.com/micro/go-micro/client" + + mock "github.com/stretchr/testify/mock" + + proto "github.com/ProtocolONE/geoip-service/pkg/proto" +) // GeoIp is an autogenerated mock type for the GeoIp type type GeoIp struct { diff --git a/pkg/mocks/HydraAdminApi.go b/pkg/mocks/HydraAdminApi.go index 9d291c5..fe81f20 100644 --- a/pkg/mocks/HydraAdminApi.go +++ b/pkg/mocks/HydraAdminApi.go @@ -2,9 +2,12 @@ package mocks -import admin "github.com/ory/hydra-client-go/client/admin" -import mock "github.com/stretchr/testify/mock" -import runtime "github.com/go-openapi/runtime" +import ( + admin "github.com/ory/hydra-client-go/client/admin" + mock "github.com/stretchr/testify/mock" + + runtime "github.com/go-openapi/runtime" +) // HydraAdminApi is an autogenerated mock type for the HydraAdminApi type type HydraAdminApi struct { diff --git a/pkg/mocks/InternalRegistry.go b/pkg/mocks/InternalRegistry.go index e2c4bfd..9e96a62 100644 --- a/pkg/mocks/InternalRegistry.go +++ b/pkg/mocks/InternalRegistry.go @@ -2,10 +2,14 @@ package mocks -import database "github.com/ProtocolONE/auth1.protocol.one/pkg/database" -import mock "github.com/stretchr/testify/mock" -import persist "github.com/ProtocolONE/auth1.protocol.one/pkg/persist" -import service "github.com/ProtocolONE/auth1.protocol.one/pkg/service" +import ( + database "github.com/ProtocolONE/auth1.protocol.one/pkg/database" + mock "github.com/stretchr/testify/mock" + + persist "github.com/ProtocolONE/auth1.protocol.one/pkg/persist" + + service "github.com/ProtocolONE/auth1.protocol.one/pkg/service" +) // InternalRegistry is an autogenerated mock type for the InternalRegistry type type InternalRegistry struct { @@ -156,6 +160,22 @@ func (_m *InternalRegistry) OneTimeTokenService() service.OneTimeTokenServiceInt return r0 } +// SpaceService provides a mock function with given fields: +func (_m *InternalRegistry) SpaceService() service.SpaceServiceInterface { + ret := _m.Called() + + var r0 service.SpaceServiceInterface + if rf, ok := ret.Get(0).(func() service.SpaceServiceInterface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(service.SpaceServiceInterface) + } + } + + return r0 +} + // Watcher provides a mock function with given fields: func (_m *InternalRegistry) Watcher() persist.Watcher { ret := _m.Called() diff --git a/pkg/mocks/LauncherTokenServiceInterface.go b/pkg/mocks/LauncherTokenServiceInterface.go index c4d428f..79b638e 100644 --- a/pkg/mocks/LauncherTokenServiceInterface.go +++ b/pkg/mocks/LauncherTokenServiceInterface.go @@ -2,8 +2,10 @@ package mocks -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + mock "github.com/stretchr/testify/mock" +) // LauncherTokenServiceInterface is an autogenerated mock type for the LauncherTokenServiceInterface type type LauncherTokenServiceInterface struct { diff --git a/pkg/mocks/MfaApiInterface.go b/pkg/mocks/MfaApiInterface.go index 9a044be..48f96a3 100644 --- a/pkg/mocks/MfaApiInterface.go +++ b/pkg/mocks/MfaApiInterface.go @@ -2,10 +2,15 @@ package mocks -import client "github.com/micro/go-micro/client" -import context "context" -import mock "github.com/stretchr/testify/mock" -import proto "github.com/ProtocolONE/mfa-service/pkg/proto" +import ( + context "context" + + client "github.com/micro/go-micro/client" + + mock "github.com/stretchr/testify/mock" + + proto "github.com/ProtocolONE/mfa-service/pkg/proto" +) // MfaApiInterface is an autogenerated mock type for the MfaApiInterface type type MfaApiInterface struct { diff --git a/pkg/mocks/MfaServiceInterface.go b/pkg/mocks/MfaServiceInterface.go index 5b330ca..d716600 100644 --- a/pkg/mocks/MfaServiceInterface.go +++ b/pkg/mocks/MfaServiceInterface.go @@ -2,9 +2,12 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // MfaServiceInterface is an autogenerated mock type for the MfaServiceInterface type type MfaServiceInterface struct { diff --git a/pkg/mocks/OneTimeTokenServiceInterface.go b/pkg/mocks/OneTimeTokenServiceInterface.go index 4eddb8c..d2d7a78 100644 --- a/pkg/mocks/OneTimeTokenServiceInterface.go +++ b/pkg/mocks/OneTimeTokenServiceInterface.go @@ -2,8 +2,10 @@ package mocks -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" + mock "github.com/stretchr/testify/mock" +) // OneTimeTokenServiceInterface is an autogenerated mock type for the OneTimeTokenServiceInterface type type OneTimeTokenServiceInterface struct { diff --git a/pkg/mocks/SessionService.go b/pkg/mocks/SessionService.go index 9af415c..ba880be 100644 --- a/pkg/mocks/SessionService.go +++ b/pkg/mocks/SessionService.go @@ -2,8 +2,10 @@ package mocks -import echo "github.com/labstack/echo/v4" -import mock "github.com/stretchr/testify/mock" +import ( + echo "github.com/labstack/echo/v4" + mock "github.com/stretchr/testify/mock" +) // SessionService is an autogenerated mock type for the SessionService type type SessionService struct { diff --git a/pkg/mocks/SpaceServiceInterface.go b/pkg/mocks/SpaceServiceInterface.go index 449af1a..dcebd9b 100644 --- a/pkg/mocks/SpaceServiceInterface.go +++ b/pkg/mocks/SpaceServiceInterface.go @@ -2,9 +2,12 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // SpaceServiceInterface is an autogenerated mock type for the SpaceServiceInterface type type SpaceServiceInterface struct { diff --git a/pkg/mocks/UserIdentityServiceInterface.go b/pkg/mocks/UserIdentityServiceInterface.go index 52cee35..2e88f44 100644 --- a/pkg/mocks/UserIdentityServiceInterface.go +++ b/pkg/mocks/UserIdentityServiceInterface.go @@ -2,22 +2,25 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // UserIdentityServiceInterface is an autogenerated mock type for the UserIdentityServiceInterface type type UserIdentityServiceInterface struct { mock.Mock } -// Create provides a mock function with given fields: _a0 -func (_m *UserIdentityServiceInterface) Create(_a0 *models.UserIdentity) error { - ret := _m.Called(_a0) +// Create provides a mock function with given fields: userIdentity +func (_m *UserIdentityServiceInterface) Create(userIdentity *models.UserIdentity) error { + ret := _m.Called(userIdentity) var r0 error if rf, ok := ret.Get(0).(func(*models.UserIdentity) error); ok { - r0 = rf(_a0) + r0 = rf(userIdentity) } else { r0 = ret.Error(0) } @@ -25,13 +28,13 @@ func (_m *UserIdentityServiceInterface) Create(_a0 *models.UserIdentity) error { return r0 } -// FindByUser provides a mock function with given fields: app, ip, userId -func (_m *UserIdentityServiceInterface) FindByUser(app *models.Application, ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) { - ret := _m.Called(app, ip, userId) +// FindByUser provides a mock function with given fields: ip, userId +func (_m *UserIdentityServiceInterface) FindByUser(ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) { + ret := _m.Called(ip, userId) var r0 *models.UserIdentity - if rf, ok := ret.Get(0).(func(*models.Application, *models.AppIdentityProvider, bson.ObjectId) *models.UserIdentity); ok { - r0 = rf(app, ip, userId) + if rf, ok := ret.Get(0).(func(*models.AppIdentityProvider, bson.ObjectId) *models.UserIdentity); ok { + r0 = rf(ip, userId) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.UserIdentity) @@ -39,8 +42,8 @@ func (_m *UserIdentityServiceInterface) FindByUser(app *models.Application, ip * } var r1 error - if rf, ok := ret.Get(1).(func(*models.Application, *models.AppIdentityProvider, bson.ObjectId) error); ok { - r1 = rf(app, ip, userId) + if rf, ok := ret.Get(1).(func(*models.AppIdentityProvider, bson.ObjectId) error); ok { + r1 = rf(ip, userId) } else { r1 = ret.Error(1) } @@ -48,13 +51,13 @@ func (_m *UserIdentityServiceInterface) FindByUser(app *models.Application, ip * return r0, r1 } -// Get provides a mock function with given fields: _a0, _a1, _a2 -func (_m *UserIdentityServiceInterface) Get(_a0 *models.Application, _a1 *models.AppIdentityProvider, _a2 string) (*models.UserIdentity, error) { - ret := _m.Called(_a0, _a1, _a2) +// Get provides a mock function with given fields: ip, externalID +func (_m *UserIdentityServiceInterface) Get(ip *models.AppIdentityProvider, externalID string) (*models.UserIdentity, error) { + ret := _m.Called(ip, externalID) var r0 *models.UserIdentity - if rf, ok := ret.Get(0).(func(*models.Application, *models.AppIdentityProvider, string) *models.UserIdentity); ok { - r0 = rf(_a0, _a1, _a2) + if rf, ok := ret.Get(0).(func(*models.AppIdentityProvider, string) *models.UserIdentity); ok { + r0 = rf(ip, externalID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.UserIdentity) @@ -62,8 +65,8 @@ func (_m *UserIdentityServiceInterface) Get(_a0 *models.Application, _a1 *models } var r1 error - if rf, ok := ret.Get(1).(func(*models.Application, *models.AppIdentityProvider, string) error); ok { - r1 = rf(_a0, _a1, _a2) + if rf, ok := ret.Get(1).(func(*models.AppIdentityProvider, string) error); ok { + r1 = rf(ip, externalID) } else { r1 = ret.Error(1) } @@ -71,13 +74,13 @@ func (_m *UserIdentityServiceInterface) Get(_a0 *models.Application, _a1 *models return r0, r1 } -// Update provides a mock function with given fields: _a0 -func (_m *UserIdentityServiceInterface) Update(_a0 *models.UserIdentity) error { - ret := _m.Called(_a0) +// Update provides a mock function with given fields: userIdentity +func (_m *UserIdentityServiceInterface) Update(userIdentity *models.UserIdentity) error { + ret := _m.Called(userIdentity) var r0 error if rf, ok := ret.Get(0).(func(*models.UserIdentity) error); ok { - r0 = rf(_a0) + r0 = rf(userIdentity) } else { r0 = ret.Error(0) } diff --git a/pkg/mocks/UserServiceInterface.go b/pkg/mocks/UserServiceInterface.go index 291910a..8df2d2a 100644 --- a/pkg/mocks/UserServiceInterface.go +++ b/pkg/mocks/UserServiceInterface.go @@ -2,9 +2,12 @@ package mocks -import bson "github.com/globalsign/mgo/bson" -import mock "github.com/stretchr/testify/mock" -import models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +import ( + bson "github.com/globalsign/mgo/bson" + mock "github.com/stretchr/testify/mock" + + models "github.com/ProtocolONE/auth1.protocol.one/pkg/models" +) // UserServiceInterface is an autogenerated mock type for the UserServiceInterface type type UserServiceInterface struct { @@ -48,20 +51,20 @@ func (_m *UserServiceInterface) Get(_a0 bson.ObjectId) (*models.User, error) { return r0, r1 } -// IsUsernameFree provides a mock function with given fields: username, appID -func (_m *UserServiceInterface) IsUsernameFree(username string, appID bson.ObjectId) (bool, error) { - ret := _m.Called(username, appID) +// IsUsernameFree provides a mock function with given fields: username, spaceID +func (_m *UserServiceInterface) IsUsernameFree(username string, spaceID bson.ObjectId) (bool, error) { + ret := _m.Called(username, spaceID) var r0 bool if rf, ok := ret.Get(0).(func(string, bson.ObjectId) bool); ok { - r0 = rf(username, appID) + r0 = rf(username, spaceID) } else { r0 = ret.Get(0).(bool) } var r1 error if rf, ok := ret.Get(1).(func(string, bson.ObjectId) error); ok { - r1 = rf(username, appID) + r1 = rf(username, spaceID) } else { r1 = ret.Error(1) } diff --git a/pkg/models/space.go b/pkg/models/space.go index c6de60a..6e48a3c 100644 --- a/pkg/models/space.go +++ b/pkg/models/space.go @@ -1,18 +1,26 @@ package models import ( + "time" + "github.com/globalsign/mgo/bson" "go.uber.org/zap/zapcore" - "time" ) type Space struct { - Id bson.ObjectId `bson:"_id" json:"id"` // unique space identifier + ID bson.ObjectId `bson:"_id" json:"id"` // unique space identifier Name string `bson:"name" json:"name" validate:"required"` // space name Description string `bson:"description" json:"description"` // space description IsActive bool `bson:"is_active" json:"is_active"` // is space active - CreatedAt time.Time `bson:"created_at" json:"-"` // date of create space - UpdatedAt time.Time `bson:"updated_at" json:"-"` // date of update space + + // UniqueUsernames determines whether app users must have unique usernames + UniqueUsernames bool `bson:"unique_usernames" json:"unique_usernames"` + + // RequiresCaptcha determines whether app users must have complete captcha verification + RequiresCaptcha bool `bson:"requires_captcha" json:"requires_captcha"` + + CreatedAt time.Time `bson:"created_at" json:"-"` // date of create space + UpdatedAt time.Time `bson:"updated_at" json:"-"` // date of update space } type SpaceForm struct { @@ -22,7 +30,7 @@ type SpaceForm struct { } func (s *Space) MarshalLogObject(enc zapcore.ObjectEncoder) error { - enc.AddString("id", s.Id.String()) + enc.AddString("id", s.ID.String()) enc.AddString("name", s.Name) enc.AddString("description", s.Name) enc.AddBool("isActive", s.IsActive) diff --git a/pkg/models/user.go b/pkg/models/user.go index 660f35a..4dfacac 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -12,7 +12,10 @@ type User struct { // ID is the id of user. ID bson.ObjectId `bson:"_id" json:"id"` - // AppID is the id of the application. + // SpaceID is the id of space to which user belongs + SpaceID bson.ObjectId `bson:"space_id" json:"space_id"` + + // AppID is the id of the application. DEPRICATED AppID bson.ObjectId `bson:"app_id" json:"app_id"` // Email is the email address of the user. @@ -142,7 +145,7 @@ type LoginPageForm struct { func (a *User) MarshalLogObject(enc zapcore.ObjectEncoder) error { enc.AddString("ID", a.ID.String()) - enc.AddString("ApplicationID", a.AppID.String()) + enc.AddString("SpaceID", a.SpaceID.String()) enc.AddString("Email", a.Email) enc.AddBool("EmailVerified", a.EmailVerified) enc.AddTime("CreatedAt", a.CreatedAt) diff --git a/pkg/service/registry.go b/pkg/service/registry.go index bf6423a..775794d 100644 --- a/pkg/service/registry.go +++ b/pkg/service/registry.go @@ -25,6 +25,9 @@ type InternalRegistry interface { // ApplicationService return instance of the application service. ApplicationService() ApplicationServiceInterface + // SpaceService return instance of the space service. + SpaceService() SpaceServiceInterface + // OneTimeTokenService return instance of the one time token service. OneTimeTokenService() OneTimeTokenServiceInterface diff --git a/pkg/service/registry_base.go b/pkg/service/registry_base.go index 0a34de3..2a8220b 100644 --- a/pkg/service/registry_base.go +++ b/pkg/service/registry_base.go @@ -12,6 +12,7 @@ type RegistryBase struct { redis *redis.Client session database.MgoSession as ApplicationServiceInterface + spaces SpaceServiceInterface ott OneTimeTokenServiceInterface lts LauncherTokenServiceInterface watcher persist.Watcher @@ -58,6 +59,7 @@ func NewRegistryBase(config *RegistryConfig) InternalRegistry { ott: NewOneTimeTokenService(config.RedisClient), lts: NewLauncherTokenService(config.RedisClient), cent: config.CentrifugoService, + spaces: NewSpaceService(config.MgoSession), } r.as = NewApplicationService(r) @@ -96,6 +98,10 @@ func (r *RegistryBase) ApplicationService() ApplicationServiceInterface { return r.as } +func (r *RegistryBase) SpaceService() SpaceServiceInterface { + return r.spaces +} + func (r *RegistryBase) OneTimeTokenService() OneTimeTokenServiceInterface { return r.ott } diff --git a/pkg/service/space.go b/pkg/service/space.go index 811c20a..e8a1ebd 100644 --- a/pkg/service/space.go +++ b/pkg/service/space.go @@ -30,7 +30,7 @@ func (ss SpaceService) CreateSpace(space *models.Space) error { } func (ss SpaceService) UpdateSpace(space *models.Space) error { - if err := ss.db.C(database.TableSpace).UpdateId(space.Id, space); err != nil { + if err := ss.db.C(database.TableSpace).UpdateId(space.ID, space); err != nil { return err } diff --git a/pkg/service/user.go b/pkg/service/user.go index edcba6e..e8f3a60 100644 --- a/pkg/service/user.go +++ b/pkg/service/user.go @@ -19,7 +19,7 @@ type UserServiceInterface interface { Get(bson.ObjectId) (*models.User, error) // IsUsernameFree checks if username is available for signup - IsUsernameFree(username string, appID bson.ObjectId) (bool, error) + IsUsernameFree(username string, spaceID bson.ObjectId) (bool, error) } // UserService is the user service. @@ -59,8 +59,8 @@ func (us UserService) Get(id bson.ObjectId) (*models.User, error) { return u, nil } -func (us UserService) IsUsernameFree(username string, appID bson.ObjectId) (bool, error) { +func (us UserService) IsUsernameFree(username string, spaceID bson.ObjectId) (bool, error) { // TODO: Optimize for case when multiple same username allowed - n, err := us.db.C(database.TableUser).Find(bson.M{"username": username, "app_id": appID}).Count() + n, err := us.db.C(database.TableUser).Find(bson.M{"username": username, "space_id": spaceID}).Count() return n == 0, err } diff --git a/pkg/service/user_identity.go b/pkg/service/user_identity.go index cf4df14..6a07697 100644 --- a/pkg/service/user_identity.go +++ b/pkg/service/user_identity.go @@ -10,16 +10,16 @@ import ( // UserIdentityServiceInterface describes of methods for the user identity service. type UserIdentityServiceInterface interface { // Create creates a new user identity. - Create(*models.UserIdentity) error + Create(userIdentity *models.UserIdentity) error // Update updates user identity data. - Update(*models.UserIdentity) error + Update(userIdentity *models.UserIdentity) error // Get return the user identity by id. - Get(*models.Application, *models.AppIdentityProvider, string) (*models.UserIdentity, error) + Get(ip *models.AppIdentityProvider, externalID string) (*models.UserIdentity, error) // FindByUser return identity by userId - FindByUser(app *models.Application, ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) + FindByUser(ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) } // UserIdentityService is the user identity service. @@ -49,10 +49,10 @@ func (us UserIdentityService) Update(userIdentity *models.UserIdentity) error { return nil } -func (us UserIdentityService) FindByUser(app *models.Application, ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) { +func (us UserIdentityService) FindByUser(ip *models.AppIdentityProvider, userId bson.ObjectId) (*models.UserIdentity, error) { ui := &models.UserIdentity{} if err := us.db.C(database.TableUserIdentity). - Find(bson.M{"app_id": app.ID, "identity_provider_id": ip.ID, "user_id": userId}). + Find(bson.M{"identity_provider_id": ip.ID, "user_id": userId}). One(&ui); err != nil { return nil, err } @@ -60,10 +60,10 @@ func (us UserIdentityService) FindByUser(app *models.Application, ip *models.App return ui, nil } -func (us UserIdentityService) Get(app *models.Application, identityProvider *models.AppIdentityProvider, externalId string) (*models.UserIdentity, error) { +func (us UserIdentityService) Get(identityProvider *models.AppIdentityProvider, externalId string) (*models.UserIdentity, error) { ui := &models.UserIdentity{} if err := us.db.C(database.TableUserIdentity). - Find(bson.M{"app_id": app.ID, "identity_provider_id": identityProvider.ID, "external_id": externalId}). + Find(bson.M{"identity_provider_id": identityProvider.ID, "external_id": externalId}). One(&ui); err != nil { return nil, err } From abd72fb805730775e1657373fa006f658735dd03 Mon Sep 17 00:00:00 2001 From: Serge Date: Tue, 14 Apr 2020 20:52:04 +0500 Subject: [PATCH 184/251] fix: ws notification on challenge expiration --- pkg/api/centrifugo.go | 21 +++++---------------- pkg/service/centrifugo.go | 10 ++++++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/pkg/api/centrifugo.go b/pkg/api/centrifugo.go index 0babcbe..2c94880 100644 --- a/pkg/api/centrifugo.go +++ b/pkg/api/centrifugo.go @@ -4,9 +4,7 @@ import ( "net/http" "time" - "github.com/ProtocolONE/auth1.protocol.one/pkg/api/apierror" "github.com/ProtocolONE/auth1.protocol.one/pkg/config" - "github.com/ProtocolONE/auth1.protocol.one/pkg/models" "github.com/ProtocolONE/auth1.protocol.one/pkg/service" "github.com/centrifugal/gocent" "github.com/labstack/echo/v4" @@ -65,21 +63,12 @@ func (c *Centrifugo) Refresh(ctx echo.Context) error { }) } - t := &models.LauncherToken{} - err = c.registry.LauncherTokenService().Get(challenge.Value, t) - if err != nil { - if err == apierror.NotFound { - return ctx.JSON(http.StatusBadRequest, map[string]interface{}{ - "result": map[string]string{ - "error": err.Error(), - }, - }) - } - } - + c.registry.CentrifugoService().Expired(challenge.Value) return ctx.JSON(http.StatusOK, map[string]interface{}{ - "result": map[string]interface{}{ - "expire_at": time.Now().Add(time.Second * time.Duration(c.config.SessionTTL)).Unix(), + "disconnect": map[string]interface{}{ + "code": 4404, + "reconnect": false, + "reason": "expired", }, }) } diff --git a/pkg/service/centrifugo.go b/pkg/service/centrifugo.go index e60ea9d..32ab2d5 100644 --- a/pkg/service/centrifugo.go +++ b/pkg/service/centrifugo.go @@ -12,6 +12,7 @@ import ( type CentrifugoServiceInterface interface { InProgress(loginChallenge string) error Success(loginChallenge, url string) error + Expired(loginChallenge string) error } type Centrifugo struct { @@ -48,3 +49,12 @@ func (c *Centrifugo) Success(loginChallenge, url string) error { return c.client.Publish(ctx, fmt.Sprintf("%s#%s", c.config.LauncherChannel, loginChallenge), data) } + +func (c *Centrifugo) Expired(loginChallenge string) error { + ctx := context.Background() + data, _ := json.Marshal(map[string]string{ + "status": "expired", + }) + + return c.client.Publish(ctx, fmt.Sprintf("%s#%s", c.config.LauncherChannel, loginChallenge), data) +} From 4585bc533d49dfbf24f424f36d2c51c5da368473 Mon Sep 17 00:00:00 2001 From: Snezhana Dorogova Date: Wed, 15 Apr 2020 17:00:04 +0300 Subject: [PATCH 185/251] docs: update readme --- README.md | 67 ++++++++++++++++++++++++++--------------------- qilin-schema.png | Bin 0 -> 247469 bytes 2 files changed, 37 insertions(+), 30 deletions(-) create mode 100644 qilin-schema.png diff --git a/README.md b/README.md index f8d3aec..74bdf53 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,26 @@ -# AuthOne Introduction +# AuthOne -AuthOne is an open source authorization server that supports the OAuth 2.0 and OpenID 1.0 Connect paradigm, created on -the basis of the [ORY Hydra](https://github.com/ory/hydra) open source protected and certified application. -The server is not integrated into your application, but is used as an external service according to OAuth authorization -standards. - -[![Build Status](https://travis-ci.org/ProtocolONE/auth1.protocol.one.svg?branch=master)](https://travis-ci.org/ProtocolONE/auth1.protocol.one) -[![codecov](https://codecov.io/gh/ProtocolONE/auth1.protocol.one/branch/master/graph/badge.svg)](https://codecov.io/gh/ProtocolONE/auth1.protocol.one) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Build Status](https://travis-ci.com/ProtocolONE/auth1.protocol.one.svg?branch=develop)](https://travis-ci.com/ProtocolONE/auth1.protocol.one) +[![codecov](https://codecov.io/gh/ProtocolONE/auth1.protocol.one/branch/develop/graph/badge.svg)](https://codecov.io/gh/ProtocolONE/auth1.protocol.one) [![Go Report Card](https://goreportcard.com/badge/github.com/ProtocolONE/auth1.protocol.one)](https://goreportcard.com/report/github.com/ProtocolONE/auth1.protocol.one) -[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/ProtocolONE/auth1.protocol.one) + +Qilin is an open-source digital distribution platform for game developers and publishers. Our mission is to distribute games by minimizing the effort of contracting, sharing documentation and providing comprehensive real-time statistics. + +Our solution is part of Protocol One IAAS and is actively used in the Storefront constructor. Qilin can be used as a component in an existing P1-independent system, using its hardware or cloud platforms. + +**Qilin architecture schema** + +![Qilin architecture schema](qilin-schema.png) + +**AuthOne** is an open-source authorization server that supports the OAuth 2.0 and OpenID 1.0 Connect paradigm, created based on the [ORY Hydra](https://github.com/ory/hydra) open source protected and certified application. +The server is used as an external service according to OAuth authorization standards. --- -### Table of Contents +## Table of Contents + - [Installation](#installation) - [Configuration](#configuration) - [Usage](#usage) @@ -21,12 +29,13 @@ standards. - [License](#license) ## Installation + For the authorization server to work, you will need: -* [Go](https://golang.org/) -* [MongoDB](https://www.mongodb.com/) -* [Redis](https://redis.io/) -* [ORY Hydra](https://github.com/ory/hydra) and its dependencies. -* Server to send mail +- [Go](https://golang.org/) +- [MongoDB](https://www.mongodb.com/) +- [Redis](https://redis.io/) +- [ORY Hydra](https://github.com/ory/hydra) and its dependencies. +- Server to send mail You can install all services separately, or use the prepared Docker for a comprehensive installation of all components. The docker-compose file contains the basic configuration of the application, which you can modify to suit your needs. @@ -38,7 +47,8 @@ access is provided only to public methods (see the configuration example in the Calls to administrative methods are available only from the internal subnet for security purposes. ## Configuration -To start the application, you can use the following configuration parameters in the environment variables: + +To start the application, configure the following environment variables: | Variable | Default | Description | |----------------------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------| @@ -71,8 +81,8 @@ To start the application, you can use the following configuration parameters in | AUTHONE_MIGRATION_DIRECT | | Used to migrate a database. If not specified, no migration is used. Acceptable values of up and down. | | AUTHONE_AUTH_WEB_FORM_SDK_URL | | URL to the java-script file with SDK authorization. | -***Attention!*** Do not forget that ORY Hydra provides its configuration parameters that also need to be configured. -For more information on this, see the project website - https://github.com/ory/hydra. +> **Attention!** Do not forget that ORY Hydra provides its configuration parameters that also need to be configured. +For more information on this, see the [ORY Hydra project website](https://github.com/ory/hydra). ## Usage @@ -83,7 +93,7 @@ Compile the application into an executable file and run it with the `server` key Using the [API](#api), you need to create a space, an application and, if necessary, adjust its parameters (criteria for passwords, the duration and expiration of one-time tokens, identity providers for user accounts, etc.). -Space? What is it and why is it needed? +### What is Space? Space is the union of one or more applications within a single ecosystem. This can often be required to separate users in different projects (for example, site A and site B) for sharing access @@ -116,21 +126,18 @@ See an example of use in the demo application located in the [AuthOne JWT](https://github.com/ProtocolONE/authone-jwt-verifier-golang) project. ## Getting Started + Here you will find instructions on how to launch an authorization server in a few steps, create an application and start registering and authorizing users. - Start the authorization server using the docker-compose: `docker-compose up` - Using API and Postman create space. ![Create space](public/images/docs/postman_create-space.png) -- Using the resulting space ID, create an application. In the auth_redirect_urls parameter, specify the address to -which the user will be redirected after successful registration or authorization. +- Using the resulting space ID, create an application. In the auth_redirect_urls parameter, specify the address to which the user will be redirected after successful registration or authorization. ![Create space](public/images/docs/postman_create-app.png) -- In your application (for example, you have a website located at http://localhost:1323) place a link to registration -and authorization, using the previously received application identifier and URL to return: +- In your application (for example, you have a website located at http://localhost:1323) place a link to registration and authorization, using the previously received application identifier and URL to return: `http://localhost/oauth2/auth?response_type=code&client_id=5cde2f3252ad75007610fa1e&redirect_uri=http%3A%2F%2Flocalhost%3A1323%2Fauth%2Fcallback&state=customstate`. -- Prepare a page to which the user will go after the end of registration or authorization (the URL that was previously -listed as redirected - `http://localhost:1323/auth/callback`). With the help of any oauth library, implement code -verification and exchange for access tokens. +- Prepare a page to which the user will go after the end of registration or authorization (the URL that was previously listed as redirected - `http://localhost:1323/auth/callback`). With the help of any OAuth library, implement code verification and exchange for access tokens. ``` import "golang.org/x/oauth2" @@ -191,6 +198,7 @@ fmt.Println(body) - Is done. Open the site and go to the registration. ## API + The application management API supports the following functionality: - Adding, editing and receiving information about the space; - Adding, editing and receiving information about the application; @@ -198,13 +206,12 @@ The application management API supports the following functionality: - Adding, editing and receiving information about the identity of the provider for the application; - Getting active for the application identity providers; - Getting a list of templates for identity providers; -- Adding MFA provider for the application; - +- Adding MFA provider for the application. + For convenience, all API requests are prepared as a [collection](spec/postman_collection) for [Postman](https://www.getpostman.com/) application where you can see a list of methods, parameters, their description and try to execute them for your copy of the authorization server. ## License -Apache License 2.0 -For the whole copyright, see the [LICENSE](LICENSE) file distributed with this source code. +The project is available as open source under the terms of the [Apache-2.0 License](https://opensource.org/licenses/Apache-2.0). \ No newline at end of file diff --git a/qilin-schema.png b/qilin-schema.png new file mode 100644 index 0000000000000000000000000000000000000000..26107ad8980b58327d0bf2a3fa381acf811b5ced GIT binary patch literal 247469 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ൖ|4lIkPW3JXlhM-&CxQ%yD1Y+Lll@3^M`$m?6D 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Ð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